Our blog contains the activity stream of Orchard Dojo: general news, new resources or tutorials are announced here.

Copilot Integration, Last call: Speaker application for Orchard Harvest 2026 - This week in Orchard (01/05/2026)

This week, Mike Alhayek shows how to use Copilot directly inside Orchard Core!

But before that, check out some code where you can see that, starting now, Orchard supports static data migration methods, and suppressions are no longer required for migration steps that don't use instance state.

Welcome the first contribution from Jack Liu, who made the pagination of the List Part configurable to decide whether to show a full pager with page numbers or just the arrows to navigate to the previous and next pages.

Do you know that since 2013, we've been working with Óbuda University in a hands-on way to teach web development? If you are interested in our Orchard Core courses at the university, check out our post on our site!

As we mentioned, we started publishing last year's Harvest recordings to YouTube. Check them out for some inspiration, and don't forget to apply to be a speaker for this year's Harvest by the 5th of May, midnight, anywhere on Earth!

Ready to explore? Let's dive in!

Latest tutorials

Featured tags

AI
IIS
MCP
API
SMS
SEO
All tags >

Monaco Editor, Introduce ResourcePosition - This week in Orchard (13/03/2021)

The Monaco Editor is the code editor that powers VS Code. And from now you can use it in Orchard Core too! Check out our post for the latest improvements of Orchard Core and don't forget to take a look at our Orchard Ambassadors Toolbox! Orchard Core updates Add some comments to DataMigration class It can happen that you don't remember the correct syntax of the methods that you need to implement when you are adding your migration classes. It's useful to have it actually written down somewhere where you don't have to search. Now if you open up the DataMigration class in the OrchardCore.Data.Abstractions project you will find some comments about the correct syntax. Introduce ResourcePosition Imagine you have multiple resources (CSS or script files) to add in the footer and they don't have any dependencies. But maybe you want one of them to be at the end because it has to happen at the end. Then you can say now I want to be this resource to be the last one. But how can you do that? You can find a RequireDependencies method in the ResourceManagerTest that is about to test this new feature. Let's take a look! Here you can see that we defined a resource with the name first-resource and used the SetPosition method to set the position. The first-resource has one dependency: the first-dependency one that we have already defined in line 127. The code should inject the first-resource first but because it has a dependency to the first-dependency, the logic will inject the first-dependency resource first, then it will inject the first-resource resource. The same applies when you use the ResourcePosition.Last enum. We said that we want to define two resources as the last ones: the last-dependency and the last-resource. But the last-resource has a dependency on the last-dependency, and the last-dependency has a dependency on the another-dependency, so the correct order will be: another-dependency, last-dependency, and last-resource. Provide AdminUserId and other properties to recipes People are using recipe migrations (like the RecipeMigrator) to create content items because they can. But when you run them from setup or when you run a setup on a site, this doesn't set up some properties, like the owner of the content item. Now there is a new interface called IRecipeEnvironmentProvider that you can implement to provide different things to the recipes. The RecipeEnvironmentFeatureProvider is used to populate the environment with the AdminUserId, AdminUsername, and SiteName values that you can use when you are executing your recipes. Fix Active Directory logs an unnecessary warning during setup Let's say you activated the OrchardCore.Microsoft.Authentication.AzureAD feature during setup and configured it from the same recipe in the next step. You will see that the site is up and running but there is a warning in the log: OrchardCore.Microsoft.Authentication.Configuration.AzureADOptionsConfiguration|WARN|The AzureAD Authentication is not correctly configured. This has been fixed now by using LoadSettings() in place of GetSettings() for updating the settings in the related recipe steps. The authentication settings being entities held by the SiteSettings document, so as done in other places and for all shared documents. Demos Monaco Editor Monaco Editor is a new editor mode that is available for the Html Field. The Monaco Editor is the code editor that powers VS Code. A good page describing the code editor's features is here. Now let's see this editor in action! Let's say you set up your site using the Blog recipe. The Blog recipe contains an Article content type that will be perfect for us to play with. Head to the admin UI of Orchard Core and modify the content definition of the Article content type (Content -> Content Definition -> Content Types -> Article). Let's add a new Html Field to this content type and name it Monaco for example. Don't forget to Edit that Html Field and set the editor mode of that field to Monaco editor. You will see that there is a text area that you can use to configure the options of the editor. If you click on the Documentation for options link below you will be navigated to a page that explains which kind of options you can use in the configuration. Leave it on the default that means the editor will use the HTML language. Now if you save the content definition of the Article content type and edit the predefined Article content item, you will see the new field that you can use. You can see that it's the same editor as you can use in Visual Studio code. In this GIF we just showed you some minor functions of the editor by using the default options. But as we mentioned you can configure your editor as you want. Let's say you would like to change the theme of the editor. Modify the editor options and set the value of the theme string that is the initial theme to be used for rendering. The current out-of-the-box available themes are vs (default), vs-dark, hc-black. Let's try out the last one. There is a playground where you can find several examples to see how to use the different kinds of options. If you would like to know more about the Monaco Editor for Orchard Core, head to YouTube for a recording! Use custom settings to customize your theme In Orchard Core, you have the option to add as many settings to your site as you want. By using these settings you can set up some basic stuff like the name of the site, the default time zone, or the page title format. Some modules can provide their own settings. For example, if you enable the Facebook module, you can set the AppId, the AppSecret parameters that are necessary to make the connection between your site and a Facebook App. You can create a theme that can be easily customized just by using settings from the admin UI. To do that you need to implement your theme to support customization. But if you do that you can easily say what kind of navbar, header, logo, etc. you would like to use. Check out the following recording to see what you can achieve if you already have a theme like that. News from the community Orchard Ambassadors Toolbox Let us introduce the Orchard Ambassadors Toolbox! This repository contains a package of useful tools and content for those who want to evangelize Orchard Core. Check out the Readme.md file of the repository for a detailed description of what you can find in the repository. And if you followed us on YouTube, you may have seen our Showcasing Orchard Core CMS video that is also based on this template. Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 192 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Parlot, Make deployment steps orderable - This week in Orchard (07/03/2021)

This week you can meet with Parlot, which is a fast, lightweight, and simple to use .NET parser combinator! Check out our post for the orderable deployment steps, the improvements of the Kast platform, and many more! Orchard Core updates Make deployment steps orderable This is about making deployment steps orderable in the UI, to allow drag and drop to get steps where you want them to be. UI only, as the choice to when steps run should be up to the user. Let's say you have plenty of plans where features don't want to be first - more common when deploying to existing sites, rather than building up recipes, but steps are for both. And now you can also find hints to the important steps that suggest they should go first, like "Content Definitions should be placed before any content steps." Update from node-sass to dart-sass This is about replacing gulp-sass with its newer gulp-dart-sass because node-saas is now deprecated and the latest node-sass doesn't compile on the latest NodeJS anymore. So, it's recommended on the gulp-sass repository be upgraded to gulp-dart-sass as node-sass is deprecated. You can read more about it in this article. Fix WorkflowBlockingActivitiesIndex table indices name length for PostgreSQL This is an interesting one, so we think this should deserve a few lines. Check out the Migrations file in the OrchardCore.Workflows module where you can see the creation of two different indices: IDX_WorkflowBlockingActivitiesIndex_DocumentId_ActivityId and IDX_WorkflowBlockingActivitiesIndex_DocumentId_ActivityName. Because of the PostgreSQL name length limit, it uses only IDX_WorkflowBlockingActivitiesIndex_DocumentId_Activity for both which causes an exception. The fix is just to reduce the length of these indices. Add Properties to SetupContext There is a SetupContext class that had some properties like SiteName, AdminUserName, AdminUserId, etc. This SetupContext class will be prepopulated by the setup screen and then passed to ISetupHandler. But now the ISetupHandler accepts an IDictionary to work with these properties. But why is it useful? When setting up a tenant or site sometimes you need to pass in some custom data and use it in your setup recipes. Like when a user registers on a site and he submits a form with firstname, lastname, etc. We then call a workflow that creates the tenant and executes a setup recipe. In this setup recipe, we could create a landing page and we want to assign the firstname, lastname to be set as the displaytext of the landing page content item. Or another use case would be to populate the custom user profile settings during setup. So, from now, the developers can populate the Properties bag from his workflow task or a custom setup screen if they would like to. You can see a good example in the ExecuteAsync method of the SetupTenantTask. Demos Parlot The Shortcodes repository by Sébastien Ros contains a Shortcodes processor for .NET with a focus on performance and simplicity. And now that Shortcodes processor is updated to use a new parser called Parlot. Parlot is a French pronunciation of the word like chat or someone who talks a lot. In French, you write it parlotte. Parlot is a hand-written parser for Shortcodes and that parser is now extracted to make it reusable. You can find adding and using Parlot in the Shortcodes module in this PR. If you check out that pull request, you will see that before this PR we had the Character.cs, Cursor.cs classes. Now they aren't here anymore, they are in the package. The code is almost the same. Now we have a ShortcodesParser.cs that is using Parlot. And in this file, you can find the grammar of Shortcodes. A text is based on shortcode and TEXT nodes. A Shortcode can have an identifier and arguments. An argument is like identifier equals value. It's actually could be just a value if you want. And a value is either a string or a number. This class contains a bunch of first-level methods like ParseNode, ParseRawText, and so on. If you check out the JSON benchmarks of Parlot, you will see a nice table about the performance of Parlot. And in that table, you can see the performance of parsing JSON documents. As you can see, it is ten times faster than something like Sprache, which is a famous parser. Pidgin has been created to be faster than Sprache and now Parlot is faster than Pidgins. If you take a look at the allocations, you can see that they are equal because it's just about allocating JSON. This benchmark creates an expression tree (AST) representing mathematical expressions with operator precedence and grouping. Same thing here. This table is about comparing the low level, the fluent API, and Piding. Even the Fluent API is five times faster than Pidgin. And in terms of allocation, it's a little bit better than Pidgin. Here you can see a demo video about Parlot and a lot more than that! Like stories about the NCalc library that is created by Sébastien Ros 10 years ago. NCalc is a mathematical expressions evaluator in .NET. NCalc can parse any expression and evaluate the result, including static or dynamic parameters and custom functions. And that library is used by the Sprache.Calc library. Sprache.Calc provides easy to use extensible expression evaluator based on the LinqyCalculator sample. The evaluator supports arithmetic operations, custom functions, and parameters. It takes a string representation of an expression and converts it to a structured LINQ expression instance which can easily be compiled to an executable delegate. In contrast with interpreted expression evaluators such as NCalc, compiled expressions perform just as fast as native C# methods. We can fill up the whole This week in Orchard post just by these libraries and the story behind Parlot. Or we can start to describe how the parser works and how you can extend it with your own implementations, but this may no longer be closely related to the topic of this series. So, as we just mentioned before: if you are interested in these topics, this will be your presentation! Resource Zones, Resource Layers, Resource Widgets Kast is an Australian company and one of their primary goals is to implement the Kast platform with the Kast Group Finder component. We worked together with Seth Cleaver (Co-founder and Director of Kast) on this tool to be able to create an intuitive self-service process that enables people within a church to easily find a suitable group to attend, simplify the administrative processes required for getting people into groups, and provide information to the group co-ordinators that might assist in planning and measuring effectiveness. Check out this case study about how we've developed this multi-tenant social group management platform for churches! The Kast platform is growing from time to time and this time you could see an improvement from Dean Marcussen which is about providing ways to edit static resources (like JavaScript and CSS) using the admin UI. The exact issue in GitHub is opened by Dody Gunawinata a while ago about the downside of the current theme system is that to change anything will require deployment. The way around is to include the JS/CSS in a template and include them in every other template. Check out the following recording for a possible solution! It didn't seem like the design was wanted for Orchard Core itself, so it will probably remain private at this stage. But if the people wanted it, it might be possible to make it available at some point as a contribution module. News from the community Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 190 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Reimplement batching in YesSql, Azure Application Insights module - This week in Orchard (26/02/2021)

Refactoring the Content zone, reimplement batching in YesSql, hiding Setup recipes, adding more indexes to index tables, Azure Application Insights module and a lot more is waiting just for you in this post! Orchard Core updates Do not display Setup recipes in the admin UI You can easily list all of the existing recipes of your site under Configuration -> Recipes. If you create a recipe, like myrecipe.recipe.json, and put it in a Recipes folder of one of your modules, that recipe will be listed on this page. Let's add a simple one and check out the content of that page. You can see that our recipe with the display name My Recipe is on the list but wait! What happened with the other recipes? We have several other built-in recipes like the Blog, the Agency, and so on. Where are they? From now the logic in the Index method of the AdminController in the OrchardCore.Recipes module is slightly changed. If the recipe is a setup recipe (defined in the issetuprecipe of the JSON file) or has the hidden tag, the recipe will not appear in that list. You can see that our myrecipe has the false value for the issetuprecipe but the Blog recipe has the true value. Admin Dashboard Widgets We mentioned the Admin Dashboard widgets two times in This week in Orchard that allows you to add cards to the homepage of the dashboard, which is about to represent a piece of functionality of a given feature or module. You can find the first post here and the second one here. And now this feature has been merged to the dev branch of Orchard Core and there is also a new page in the Orchard Core Documentation about this module. It hasn't got too much information yet but the embedded recording could help you to see this feature in action. If you haven't heard about this feature, don't forget to check out the previous blog posts and the demo video! Use DocumentId in indexes This fix is also about using the correct combination of fields for each index that we use. For example, the index for the UserIndex table now contains every field of the table. So, from now you will find indexes for every index table. Refactor ContentZone - Tabs, Card, Column containers With more and more dynamic shapes coming into Orchard Core (all the tab/card grouping shapes, and also shapes like the ContentCard) it would be potentially useful to have a ShapesViewModel that could be used as a hard type abstract class to create specific targetted ViewModels, i.e. a TabViewModel. The problem with the ShapeViewModel is it doesn't support a list of positioned Items, so right now we are using Shape because many of these tab/card/content card shapes require a list of positioned items as well. So we was not intending that a ShapesViewModel was actually an IShape, just an abstract that could be used to build shapes with, and the mixin would still turn it into an IShape, by mixing in the ShapeViewModel which has all the required IShape properties. The idea being you could then use the IShapeFactory to create a shape, then add items to it. var shape = ShapeFactory.CreateAsync<TabViewModel>("Tab", m =>{ m.TabId = tabId});foreach(var item in thetabs){ shape.Add(item);} The current usage builds 3 different shapes, even when displaying on the front end, and there are no groups. Here we do a quick check first, to see if there are any groups, and if there are none, just render the zone directly. No extra shapes. Also Removes uses a dynamic, and moves to hard typed models. Uses ToLookup instead of GroupBy (better usage). Uses fewer dynamics for injected properties, i.e. DisplayAsync can be resolved directly to its interface instead of being dynamic (this needs evaluation, as we might do it for the other C# Shape Attributes, or not). If you check out the modifications of the ZoneShapes class, you will find the implementation of the ContentZone shape and building the TabContainer shape by using the new GroupingsViewModel. And by having the GroupingsViewModel ViewModel we can use that instead of a dynamic one as you can see in the TabContainer.cshtml file. Demos YesSql: Reimplement batching When we do updates on the content items and when one deletes a document all the index tables corresponding to the document type get a DELETE query. And this DELETE query is actually a single DELETE query. If we see a benchmark we can realize that the batching isn't working. So, if you would like to delete multiple content items, the code is just about to send multiple DELETE requests instead of sending one. If you run the query locally using SQL Server and you have 1000 indexes, it takes one second. So, you might not notice that it's slow. It's slow but it could look like that's because we have several indexes. Extra Indexes: 1, Elapsed 00:00:00.0371806Extra Indexes: 100, Elapsed 00:00:00.1317780Extra Indexes: 200, Elapsed 00:00:00.2826214Extra Indexes: 500, Elapsed 00:00:00.6213360Extra Indexes: 1000, Elapsed 00:00:01.2628232 But when you have the SQL Server in Azure, the deletion of 1000 indexes could take 28 seconds. At this point, you will start noticing the performance just after 100 indexes. Apparently, we have around 20 indexes in Orchard Core but you can quickly arrive at 100. Extra Indexes: 1, Elapsed 00:00:00.0838498Extra Indexes: 100, Elapsed 00:00:02.5644737Extra Indexes: 200, Elapsed 00:00:05.0814065Extra Indexes: 500, Elapsed 00:00:12.6558409Extra Indexes: 1000, Elapsed 00:00:28.6622291 In YesSql, when you update a document, it needs to update all the indexes, which means it will rebuild them. And an index can return multiple records like if I'm indexing the name of someone, I might want to index the first name, the last name, the middle name. These are three records, one per name. So, what it does is, it builds the three records in memory and it will send a query to delete any record that was associated with the document and then sends three inserts for the new records. So you have one for the delete and three for the inserts. But it sends a delete even for the indexes that didn't return anything because the fact that you didn't return anything might mean that there is nothing anymore associated. So you need to delete and send nothing. This way we get a delete per index. That's not optimal but that's how YesSql works and that's optimal for reads and not writes. To goal is to make reads faster than writes. Still, we should not have to send one independent query to do the deletes per index. That's what this issue is about. And Sébastien Ros managed to fix it. And here are some numbers. These are all for dummy indexes that never perform any writes. Just cause deletes. What we can see in the profiler is that everything easy to batch is batched together. The big batch with mostly deletes, and a couple of inserts, is now long-running, instead of many many short runs. Probably from the look of it, the insert is still expensive, so which pushes up the time run. Before batchingLocal Indexes 1, Elapsed 00:00:00.3004236 Indexes 100, Elapsed 00:00:00.2375774 Indexes 200, Elapsed 00:00:00.3583902 Indexes 500, Elapsed 00:00:00.7695818 Indexes 1000, Elapsed 00:00:01.2836934Remote Indexes 1, Elapsed 00:00:00.7207663 Indexes 100, Elapsed 00:00:03.3552247 Indexes 200, Elapsed 00:00:05.5547927 Indexes 500, Elapsed 00:00:13.8364514 Indexes 1000, Elapsed 00:00:27.2306443After BatchingLocal Indexes 1, Elapsed 00:00:00.2207824 Indexes 100, Elapsed 00:00:00.0910920 Indexes 200, Elapsed 00:00:00.1632908 Indexes 500, Elapsed 00:00:00.4007200 Indexes 1000, Elapsed 00:00:00.4559752RemoteIndexes 1, Elapsed 00:00:03.6326000Indexes 100, Elapsed 00:00:04.9639312Indexes 200, Elapsed 00:00:09.8273422Indexes 500, Elapsed 00:00:16.1340951Indexes 1000, Elapsed 00:00:15.2008296 And how it looks like is the following. If you create a blog post in Orchard Core and after the change, there is a single communication to the database that contains everything that you can see here. This contains creating the Document, creating the ContentItemIndex, updating the ContentItemIndex with the DocumentId, and so on. These are three indexes to update (ContentItemIndex, ContainedPartIndex and AutoroutePartIndex). insert into [Document] ([Id], [Type], [Content], [Version]) values (19, 'OrchardCore.ContentManagement.ContentItem, OrchardCore.ContentManagement.Abstractions', '{"ContentItemId":"4cpw0fnmjb1kp07dmzxx8n8ecg","ContentItemVersionId":"4953p18bj3gyy5yy82f7mj7w4y","ContentType":"BlogPost","DisplayText":"The title","Latest":true,"Published":false,"ModifiedUtc":"2020-12-31T00:31:34.3346095Z","PublishedUtc":null,"CreatedUtc":"2020-12-31T00:31:34.3346095Z","Owner":"48v9vt5vxznr5z9m1df9zmvjm8","Author":"admin","TitlePart":{"Title":"The title"},"AutoroutePart":{"Path":"blog/the-title","SetHomepage":false,"Disabled":false,"RouteContainedItems":false,"Absolute":false},"BlogPost":{"Subtitle":{"Text":"Subtitle"},"Image":{"Anchors":[],"Paths":[],"MediaTexts":[]},"Tags":{"TagNames":["Space"],"TaxonomyContentItemId":"4ykev5wxfcny7tvsahz9y64mwe","TermContentItemIds":["4nv0z7r24r1vw3sfpq7t6xws59"]},"Category":{"TaxonomyContentItemId":"4tpy2wv97bkbf0zkx8tyd1bm4q","TermContentItemIds":["4bsstr09f29rp0sgy85n9f07wj"]}},"MarkdownBodyPart":{"Markdown":"Some text"},"ContainedPart":{"ListContentItemId":"491emynv0kavbzhy40xmqv1wds","Order":0}}', 1);insert into [ContentItemIndex] ([ContentItemId], [ContentItemVersionId], [Published], [Latest], [ContentType], [ModifiedUtc], [PublishedUtc], [CreatedUtc], [Owner], [Author], [DisplayText]) values ('4cpw0fnmjb1kp07dmzxx8n8ecg', '4953p18bj3gyy5yy82f7mj7w4y', 0, 1, 'BlogPost', '2020-12-31T00:31:34', '', '2020-12-31T00:31:34', '48v9vt5vxznr5z9m1df9zmvjm8', 'admin', 'The title') ; select last_insert_rowid() [Id];update [ContentItemIndex] set [DocumentId] = 19 where [Id] = (last_insert_rowid());insert into [ContainedPartIndex] ([ListContentItemId], [Order]) values ('491emynv0kavbzhy40xmqv1wds', 0) ; select last_insert_rowid() [Id];update [ContainedPartIndex] set [DocumentId] = 19 where [Id] = (last_insert_rowid());insert into [AutoroutePartIndex] ([ContentItemId], [Path], [Published], [Latest], [ContainedContentItemId], [JsonPath]) values ('4cpw0fnmjb1kp07dmzxx8n8ecg', 'blog/the-title', 0, 1, '', '') ; select last_insert_rowid() [Id];update [AutoroutePartIndex] set [DocumentId] = 19 where [Id] = (last_insert_rowid()); When we create a blog post there aren't any delete requests, because there is nothing before but when we update we need to delete all the indexes and these calls contains unnecessary deletes because for example there is no LayerMetaDataIndex on the blog post but the logic here is hey, we are dealing with a content item and there is an index for all of the content items called LayerMetadataIndex. So it will send the delete just in case which is dumb. But you can see here for each index we have a delete and it used to be a single query communication query with the database. Now let's divide by two the part where we insert and update the indexes. Instead of having to insert something then update something for each index now, we have just inserted it. We still have all the deletes and some of them are still useless but these are quick. So we have just this request now when we update a single blog post. insert into [Document] ([Id], [Type], [Content], [Version]) values (23, 'OrchardCore.ContentManagement.ContentItem, OrchardCore.ContentManagement.Abstractions', '{"ContentItemId":"4cpw0fnmjb1kp07dmzxx8n8ecg","ContentItemVersionId":"4ypdrxm7xbndr0dvcpwaraa95g","ContentType":"BlogPost","DisplayText":"The title","Latest":true,"Published":false,"ModifiedUtc":"2020-12-31T05:55:56.8113646Z","PublishedUtc":"2020-12-31T01:22:37.7926461Z","CreatedUtc":"2020-12-31T00:31:34.3346095Z","Owner":"48v9vt5vxznr5z9m1df9zmvjm8","Author":"admin","TitlePart":{"Title":"The title"},"AutoroutePart":{"Path":"blog/the-title","SetHomepage":false,"Disabled":false,"RouteContainedItems":false,"Absolute":false},"BlogPost":{"Subtitle":{"Text":"Subtitle"},"Image":{"Anchors":[],"Paths":[],"MediaTexts":[]},"Tags":{"TagNames":["Space"],"TaxonomyContentItemId":"4ykev5wxfcny7tvsahz9y64mwe","TermContentItemIds":["4nv0z7r24r1vw3sfpq7t6xws59"]},"Category":{"TaxonomyContentItemId":"4tpy2wv97bkbf0zkx8tyd1bm4q","TermContentItemIds":["4bsstr09f29rp0sgy85n9f07wj"]}},"MarkdownBodyPart":{"Markdown":"Some text"},"ContainedPart":{"ListContentItemId":"491emynv0kavbzhy40xmqv1wds","Order":0}}', 1);delete from [ContentItemIndex] where [DocumentId] = 22;delete from [AliasPartIndex] where [DocumentId] = 22;delete from [LayerMetadataIndex] where [DocumentId] = 22;delete from [ContainedPartIndex] where [DocumentId] = 22;delete from [AutoroutePartIndex] where [DocumentId] = 22;delete from [TaxonomyIndex] where [DocumentId] = 22;insert into [ContentItemIndex] ([ContentItemId], [ContentItemVersionId], [Published], [Latest], [ContentType], [ModifiedUtc], [PublishedUtc], [CreatedUtc], [Owner], [Author], [DisplayText], [DocumentId]) values ('4cpw0fnmjb1kp07dmzxx8n8ecg', '4q3271jp1705etwnf52c0nnbwz', 1, 0, 'BlogPost', '2020-12-31T01:22:37', '2020-12-31T01:22:37', '2020-12-31T00:31:34', '48v9vt5vxznr5z9m1df9zmvjm8', 'admin', 'The title', 22) ; select last_insert_rowid() [Id];insert into [ContainedPartIndex] ([ListContentItemId], [Order], [DocumentId]) values ('491emynv0kavbzhy40xmqv1wds', 0, 22) ; select last_insert_rowid() [Id];insert into [AutoroutePartIndex] ([ContentItemId], [Path], [Published], [Latest], [ContainedContentItemId], [JsonPath], [DocumentId]) values ('4cpw0fnmjb1kp07dmzxx8n8ecg', 'blog/the-title', 1, 0, '', '', 22) ; select last_insert_rowid() [Id];insert into [TaxonomyIndex] ([TaxonomyContentItemId], [ContentItemId], [ContentType], [ContentPart], [ContentField], [TermContentItemId], [DocumentId]) values ('4ykev5wxfcny7tvsahz9y64mwe', '4cpw0fnmjb1kp07dmzxx8n8ecg', 'BlogPost', 'BlogPost', 'Tags', '4nv0z7r24r1vw3sfpq7t6xws59', 22) ; select last_insert_rowid() [Id];insert into [TaxonomyIndex] ([TaxonomyContentItemId], [ContentItemId], [ContentType], [ContentPart], [ContentField], [TermContentItemId], [DocumentId]) values ('4tpy2wv97bkbf0zkx8tyd1bm4q', '4cpw0fnmjb1kp07dmzxx8n8ecg', 'BlogPost', 'BlogPost', 'Category', '4bsstr09f29rp0sgy85n9f07wj', 22) ; select last_insert_rowid() [Id];update [Document] set [Content] = '{"ContentItemId":"4cpw0fnmjb1kp07dmzxx8n8ecg","ContentItemVersionId":"4q3271jp1705etwnf52c0nnbwz","ContentType":"BlogPost","DisplayText":"The title","Latest":false,"Published":true,"ModifiedUtc":"2020-12-31T01:22:37.6390174Z","PublishedUtc":"2020-12-31T01:22:37.7926461Z","CreatedUtc":"2020-12-31T00:31:34.3346095Z","Owner":"48v9vt5vxznr5z9m1df9zmvjm8","Author":"admin","TitlePart":{"Title":"The title"},"AutoroutePart":{"Path":"blog/the-title","SetHomepage":false,"Disabled":false,"RouteContainedItems":false,"Absolute":false},"BlogPost":{"Subtitle":{"Text":"Subtitle"},"Image":{"Anchors":[],"Paths":[],"MediaTexts":[]},"Tags":{"TagNames":["Space"],"TaxonomyContentItemId":"4ykev5wxfcny7tvsahz9y64mwe","TermContentItemIds":["4nv0z7r24r1vw3sfpq7t6xws59"]},"Category":{"TaxonomyContentItemId":"4tpy2wv97bkbf0zkx8tyd1bm4q","TermContentItemIds":["4bsstr09f29rp0sgy85n9f07wj"]}},"MarkdownBodyPart":{"Markdown":"Some text"},"ContainedPart":{"ListContentItemId":"491emynv0kavbzhy40xmqv1wds","Order":0}}', [Version] = 1 where [Id] = 22;insert into [ContentItemIndex] ([ContentItemId], [ContentItemVersionId], [Published], [Latest], [ContentType], [ModifiedUtc], [PublishedUtc], [CreatedUtc], [Owner], [Author], [DisplayText], [DocumentId]) values ('4cpw0fnmjb1kp07dmzxx8n8ecg', '4ypdrxm7xbndr0dvcpwaraa95g', 0, 1, 'BlogPost', '2020-12-31T05:55:56', '2020-12-31T01:22:37', '2020-12-31T00:31:34', '48v9vt5vxznr5z9m1df9zmvjm8', 'admin', 'The title', 23) ; select last_insert_rowid() [Id];insert into [ContainedPartIndex] ([ListContentItemId], [Order], [DocumentId]) values ('491emynv0kavbzhy40xmqv1wds', 0, 23) ; select last_insert_rowid() [Id];insert into [AutoroutePartIndex] ([ContentItemId], [Path], [Published], [Latest], [ContainedContentItemId], [JsonPath], [DocumentId]) values ('4cpw0fnmjb1kp07dmzxx8n8ecg', 'blog/the-title', 0, 1, '', '', 23) ; select last_insert_rowid() [Id]; Using the other PR we are able to teach the index when not to send deletes as there will never be any index related to this Document, so don't send deletes. After that, you can see there is no more LayerMetaDataIndex and no more AliasPartIndex calls because the blog post doesn't have these. delete from [ContentItemIndex] where [DocumentId] = 23;delete from [ContainedPartIndex] where [DocumentId] = 23;delete from [AutoroutePartIndex] where [DocumentId] = 23;delete from [TaxonomyIndex] where [DocumentId] = 23; This is by having a new method on the IndexProvider to explain when to not use the IndexProvider. So it would not even go to the Map method. In this case, we say if you don't have the AliasPart, don't use the IndexProvider. context.For<AliasPartIndex>() .When(c => c.Has<AliasPart>()) .Map(contentItem => Check out the following recording on YouTube to know more about this YesSql improvement! News from the community Lombiq Hosting - Azure Application Insights This new Orchard Core module from Lombiq enables easy integration of Azure Application Insights telemetry into Orchard. Just install the module, configure the instrumentation key from a configuration source (like the appsettings.json file) as normally for AI, and collected data will start appearing in the Azure Portal. Would like to learn more about our new module? Then head to the repository now where you can find every detail about how to set up and use that module in your site! Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 191 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Culture settings deployment step, Display New menu option - This week in Orchard (21/02/2021)

New culture settings deployment step, display new menu option, sample recipes in Try Orchard Core, and many more await in our upcoming post! Orchard Core updates Disable CDN by default A lot of people were saying that there was no way to disable the CDN easily. There were issues when you are in China and you have to disable the CDN because in that case, you don't have access to the scripts that are required. And we had some required assets on the setup screen too. After some discussion, the fix is to not use CDN by default, use the locally served assets by default even in the setup screen. If you want to use CDN resources then you have to go to the settings and enable it. To do that, just navigate to the admin UI of your site and head to Configuration -> Settings -> General. And in the Resources tab, you will find the Use framework CDN (Content Delivery Network) option to enable or disable the CDN support. You can find some lines about the disabled CDN in the docs. Add deployment step for culture settings Set up your site using the Blog recipe then navigate to Configuration -> Features under the admin UI. Here enable the Deployment and the Localization features. Now you can add multiple supported cultures to your site. To do that, head to Configuration -> Settings -> Cultures and add some cultures. Now we can easily try out the new Culture settings deployment step. All you have to do is to create a new deployment plan under Configuration -> Import/Export -> Deployment Plans and add the new Culture settings to it. If you execute the plan and open the Recipe.json file inside it, you will see the supported cultures of the site. Fix NRE when clearing out all zones Let's navigate to Design -> Settings -> Zones to manage the supported zones. Remove all zones from Available zones for Layer and hit the Save button. This means the zones do not clear but instead remaining the same. The cause is an NRE in the LayerSiteSettingsDisplayDriver when attempting to split model.Zones when null. If you happen to go edit the layer zones and you make it blank, the model.Zones here will be null. You can see the fix in the LayerSiteSettingsDisplayDriver.cs. Move tags to own ViewModel Let's say you have several taxonomy terms, multiple fields with the same taxonomy terms on the editor of your content item. And if you would like to save or publish your content item you got the Form value count limit 1024 exceeded error message. The solution is to use one JSON document containing all the Tag Term entries to update and then just send what needs to be updated instead of sending everything when you are modifying your content item. Check out the Edit and UpdateAsync methods of the TaxonomyFieldTagsDisplayDriver. Demos Display New menu option If you log in to the admin UI of Orchard Core, the first option in the admin menu called New that you can use to create Creatable content items. It can happen that you don't want to be that option in the menu because you don't need that all, you never use it. Well, here comes the good news for you! If you navigate to Configuration -> Settings -> Admin, you will find a new one here called Display New menu. If you remove the tick from the checkbox, the New option will not be available from the admin menu. You can also find a short recording on YouTube about this setting! Try Orchard Core sample recipes You may hear about the Try Orchard Core website that is a showcase for the Orchard Core content management framework: you can try how Orchard Core feels by checking out an already running demo site where you can play with Orchard as you wish. This site operates with the RC2 version of Orchard Core but if you want to go ahead with a more recent dev build of the CMS, you can do that under the https://try.orchardcore.fr URL. And there is more difference between these two sites. Let's meet with the sample recipes! First, navigate to https://try.orchardcore.fr and set up a site with the Blank recipe (the third option from the recipes). If you set up your site by following the instructions from the email, you will see that the site doesn't have any home page. Now let's navigate to the admin UI of your site and head to Configuration -> Recipes. Here you will see several recipes under the Try Orchard Core category. Let's try to run them in the given order. The first one will enable the theming engine and The Default Theme for your site and make it the current one. The second recipe (called Homepage) will create a Page content type and a page content item that will be the homepage of your site. The first one (Menu) will add a new menu item to the Main Menu that targets the homepage of your site. The Layers recipe will add an Always and a Homepage layer to your site with the Content and Footer zones. The Widget recipe will create a RawHtml content type and add a Widget in the Footer zone. You will see something like this for now: the homepage has the page content type as the homepage, a menu with one item, and a RawHTML widget in the footer. Check out the following recording on YouTube to see what can you can get if you run the rest of the recipes! News from the community Work with us! You've completed the Dojo Course, congratulations! You’re now officially an Orchard Core developer. Would you like to work on a variety of challenging Orchard Core projects with the biggest Orchard team in the world? Work with us! Just send us an e-mail to crew at lombiq.com. Please include what you’re most interested in professionally and attach around 100 lines of any kind of code that you’re especially proud of or just link to the favorite open-source project of your own on GitHub or else. Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 191 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Workflows atomicity, Inline scripts and style sheets - This week in Orchard (07/02/2021)

Workflows atomicity, support inline scripts and style sheets, admin UI sticky buttons, filter and search feature for List Part too. Do we need to tell more about the content of our current post? Let's jump into the recent news of Orchard Core! Orchard Core updates Support Inline location for styles and scripts You can specify several options when working with commonly used resources like JavaScript libraries and CSS files like using a configured CDN or appending a version hash to all local scripts and style sheets. You can also specify a location the script should load, for example, you can say that I would like to render my style sheet in the HEAD of my page. If the location is not specified or specified as Inline, the script will be inserted wherever it is placed (inline). Let's say we have a site set up using the Agency recipe. Then let's navigate to Design -> Templates on the admin UI and find the predefined Content__LandingPage template. Here we can try out the new Inline mode using Liquid helpers! Try to inject the jQuery named script inline before we render the Portfolio content items. To do that we just need to add the following line: {% script name:"jQuery", at:"Inline" %}. And as you can see in the code, there is the script HTML tag right after the jQuery script text. Filter/search feature for List Part too If you navigate to the content items list of your site (Content -> Content Items) you can use a nice search feature that you can use to filter your content items by the display text values. You can also use the quick filters to see only the draft/published items or the ones that owned by you. But you can't use this filter for the List Part lists. Until now! If you have a site with a Blog recipe, head to the Blog option on the admin UI and check out the new UI. You will see the exact same filter and search here as we have seen on the content items list. New IUserClaimsProvider interface This is about the extensibility of the ClaimsProviders. You used to have to inherit from the DefaultUserClaimsPrincipalFactory to provide all the claims but now you have a new IUserClaimsProvider interface that you can implement. There are some default ones like the EmailClaimsProvider. Workaround for DateTimeOffset in indexes The OpenIdAuthorizationIndex hasn't been sent to Dapper by YesSql correctly. Here the DateTimeOffset? hasn't been handled correctly and the workaround is to use DateTime?. So, for now, the local fix is to use DateTime? instead of DateTimeOffset? in the index provider and DateTime instead of DateTimeOffset in the migrations. Demos Sticky action buttons on the admin UI The problem is that you have to do a lot of scrolling to find the action buttons to save, publish or preview your content item. There could be several options to solve this issue but now to experiment how easy to use the implemented solution, this one only affects the Templates page right now. The idea that has been implemented is to have sticky action buttons on the top of the page instead of showing them at the bottom of the screen. If you set up your site using the Agency recipe and open the predefined template (Design -> Templates) and scroll down a little bit you will see the same screen as we show here. If you would like to see the sticky buttons in action too, head to YouTube and check out this recording. And as always, if you have any feedback or suggestion on how to solve the issue of needing to scroll down a lot to reach the action buttons, don't hesitate to share your ideas on GitHub! Workflows atomicity In this demo, you could see a workflow that has a starting activity that is about to handle an incoming HTTP GET request. This workflow will call an endpoint using an HTTP GET request 30 times using a For Loop activity. After that 30 actions finished, the workflow will publish a new content item and display a simple success notification. You could ask that what is the goal to call a given endpoint 30 times and you are right. But for this time the goal of this workflow is to demonstrate that we have a long-running workflow and this process can perfectly demonstrate that. Make sure you can only have one instance of this workflow type at the same time by putting a tick in the Single instance checkbox. Because it's a single instance if you call this workflow again without the first one has been successfully finished, the execution will wait for the first one to be finished. So, the system will only start to execute the second call after the first execution was finished with or without an error. In this demo, you can see what will happen if you do 10 concurrent requests to start this workflow. You will see 10 workflow instances instead of 1. But why? It's a singleton, you should see only one instance, right? Let's navigate to the properties of the given workflow where you will see two new options: Lock timeout and Lock expiration and give them a value in ms like 10000. Now let's try to call this workflow again using 10 concurrent requests. What will happen that now if you check out the instances of the given workflow, you will find only one item there. Check out the recording to see what are these new options exactly and how to use them correctly! News from the community Work with us! You've completed the Dojo Course, congratulations! You’re now officially an Orchard Core developer. Would you like to work on a variety of challenging Orchard Core projects with the biggest Orchard team in the world? Work with us! Just send us an e-mail to crew at lombiq.com. Please include what you’re most interested in professionally and attach around 100 lines of any kind of code that you’re especially proud of or just link to the favorite open-source project of your own on GitHub or else. Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 191 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Admin Dashboard Widgets, GitHub Issue Templates - This week in Orchard (24/01/2021)

This week we will see the new issue templates in GitHub, the new View Media Options permission, and have a demo about a nice upcoming feature called Admin Dashboard Widgets! Check out our current post for more! Orchard Core updates Adding documentation for Resources Libraries If you navigate to the OrchardCore.Resources project and open the ResourceManifest.cs file there you can see the list of the resources used by Orchard Core by default. That means if you would like to use jQuery for example in your site, you don't have to add this resource again from your theme or module because Orchard Core already has it. The goal of this table in the documentation is to collect all the used libraries with their versions. New View Media Options permission You can use the appsettings.json file to configure different media options like the supported sizes, allowed file extensions, and so on. But if you don't remember the exact values off the top of your head you had to open the appsettings.json file to check out the configuration values. To solve this issue, you can just easily navigate to Configuration -> Media -> Media Options that means you just need the admin UI of Orchard Core to see the values. And now you will find new permission called View Media Options that can be used to control who can be able to view the content of this site. GitHub Issue Templates If you found a bug while using Orchard Core or you just have a suggestion or an idea to make the CMS better, feel free to add a new issue on the GitHub page of Orchard Core. All you have to do is to select the Issues tab and click on the New issue button. This will navigate you to a new page where you can select what kind of issue you would like to submit. You can see three different kinds of options here: Bug report, Feature request, and Discussions. If you select the Discussions one, you can start a new discussion. GitHub Discussions is a collaborative communication forum for the community around an open-source project. Community members can ask and answer questions, share updates, have open-ended conversations, and follow along on decisions affecting the community's way of working. Check out the existing discussions related to Orchard Core here! But if you found a bug or have a new feature request, select from the first two options. If you do that, you will be redirected to these pages. Here you can add your issue by using nice issue templates that help us to investigate the given bug, like how can we reproduce your issue. Or if you have a feature request, the template could help us to understand better what is the problem that can be solved by adding this new feature to the system. Feel free to try out and use them when submitting new issues! Refactor media tokens This is about replacing the used Data Protection to encrypt tokens, as the encrypted token changed every server restart (because of course encryption should never produce the same value twice, for a given input). This caused the browser and/or CDN to refresh all the images every time the server is restarted/deployed. The is-cache wasn't affected by this, just the browser/CDN caches. Demos Admin Dashboard Widgets A few weeks ago we wrote about an upcoming new feature called Admin Dashboard that allows you to add cards to the homepage of the dashboard, which is about to represent a piece of functionality of a given feature or module. This feature is still under development and it has changed in the meantime a lot, so it's time to check out the newest improvements! First of all, go to Configuration -> Features and enable the Admin Dashboard feature. If you do that, you will see the following screen when you navigate back to the homepage of your dashboard. You can see one predefined card here with the title Orchard Core, and at the bottom of the card, you can see an Edit and a Delete button. Let's click on the Edit one! As you can see this is an Html Dashboard Widget content type with a Title Part and a HtmlBody Part attached. But under that, you can see a textbox called Position. By using that setting you can control the order of your widgets on the dashboard. We have just this one, so whatever you type here, this will be rendered as the first widget. If you click on the Add Widget button on the dashboard, you can create as many other Html Dashboard Widgets as you want. But now let's look under the hood and see how you can create custom dashboard widgets! Navigate to Content -> Content Definition -> Content Types and create a new type, call it Markdown Dashboard Widget. Add the Title Part, the Markdown Body Part, and the Dashboard Part to it. The Dashboard Part is the one, that you will need to attach to every content type that you would like to mark as a dashboard widget. By using that part you can set the Position of your widget. And the final thing you have to do is to set the stereotype of your content type to DashboardWidget. Now let's get back to the dashboard of the admin UI and select the Markdown Dashboard Widget after clicking on the Add Widget button. As you can see, if we set the position to 1, it will be rendered after the predefined one with the title Orchard Core. If we modify the value of the position, we can change the ordering of the widgets. But that's not all! Head to YouTube now to see a video about this upcoming new feature! News from the community Execute an Orchard Core shape into HTML sample in the Lombiq Training Demo for Orchard Core The Lombiq Training Demo for Orchard Core is a demo Orchard Core CMS module for training purposes guiding you to become an Orchard developer. You can use this module as part of a vanilla Orchard Core source that includes the full source code - which is the recommended way. You can also use it as part of a solution that uses Orchard Core NuGet packages, however, it's harder to look under the hood of Orchard Core features. And now the module just got a new sample about how to execute an Orchard Core shape into HTML! Check it out now if you're learning Orchard and you haven't seen this feature yet! Work with us! You've completed the Dojo Course, congratulations! You’re now officially an Orchard Core developer. Would you like to work on a variety of challenging Orchard Core projects with the biggest Orchard team in the world? Work with us! Just send us an e-mail to crew at lombiq.com. Please include what you’re most interested in professionally and attach around 100 lines of any kind of code that you’re especially proud of or just link to the favorite open-source project of your own on GitHub or else. Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 185 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Placements module, Admin UI improvements - This week in Orchard (17/01/2021)

This time we would like to show you the new features of the Placements module, drop a few lines about the 1.0 version of the Shortcodes module and give a recap about the latest improvements of the admin UI. Check out our post for more! Orchard Core updates Placements module V2 We can do quite everything without creating any module or theme, but it's not possible to override default placement. It could be helpful to have a UI where you can easily define placement rules. Either we can add this to Part/Field settings or add a distinct UI (like the "Templates" one) where we can define a list of placement rules. The Placements module adds an optional feature that lets the user define custom placements rules in the admin UI. This V2 of the module is a rewrite of the original one, it uses IShapePlacementProvider to provide placements at runtime. The IShapePlacementProvider interface allows to asynchronously (useful if it relies on an async placement store) build an IPlacementInfoResolver for each IBuildShapeContext. The IPlacementInfoResolver implementation keeps placement rules for the current IBuildShapeContext to be able to quickly resolve shape placements synchronously. But don't go into too many technical details right now, lets's see how you can use this feature! Set up your site using the Blank site recipe then head to Configuration -> Features to enable the Placements module. Now you will find a new option under Design, called Placement. But don't go that far! We set up our site using the Blank site recipe so we don't really have much content on our site. To test out that feature we will need to define at least one content type. Let's do it quickly! We have just created a new Page content type, added a Link Field to it, and some Parts: the Title Part, the Flow Part, and the HtmlBody Part. Let's create a new Page content item and preview it! You should see something like that: the title of the page content item, the link field, the widgets in the Flow Part, and the content of the HtmlBody Part. Now it's time to go back to our Placements module. Let's say we would like to hide the LinkField of our page. To do that, navigate to Design -> Placements and add a new placement. Call it LinkField because we would like to modify that field right now. And the Placement rules text is prepopulated with null values. To hide the Link Field, just simply modify the place value to "-". Note that this will hide every Link Field of the site! But sometimes it's not obvious how to write the placement rules correctly for the first time. You have to know some words about the content templates, shape differentiators, content part and field differentiators, and so on. And here comes another great feature of the Placements module! Let's say we would like to hide the editor of the link field. Navigate to Content -> Content Definition -> Content Types and select the Page. Hit Edit and Edit again near the Link Field. Here you will find a new Edit placements button that contains some predefined placements for our Link Field (named Source). If you click some of those, a new placement will be created. Let's select Placement in admin editor for the Source field in a Page. This will generate the following placement: As you can see here, the type of shape is LinkField_Edit and the differentiator has the Page-Source value. That means to target the editor of the Link Field called Source of the Page content type. If you say "-" for the place, it will hide the editor of the Link Field when creating or editing Page content items. New IsImageFile Orchard helper Instead of using a RegEx or something like that, there is now a new IsImageFile Orchard helper that uses a static HashSet that contains the possible allowed file extensions that an image file could have. Just use this helper to determine if a path is an image file. Shortcodes 1.0.0 is here There is a Shortcodes module in GitHub created by Sébastien Ros that is a shortcodes processor for .NET with a focus on performance and simplicity. It allows text content editors to inject specialized content blocks using custom arguments, like images, Twitter embeds, youtube videos, only with simple blocks like [video 123]. It has several features, like supporting async shortcode to execute database queries and async operations more efficiently under load or supporting named and positioned arguments. And this is the library that is integrated into Orchard Core to be able to work with shortcodes. We mentioned the Shortcodes feature of the CMS several times in This week in Orchard, for example here, now let's focus on the latest changes of the module. The big news is now this module was come out from the beta version! Let's mention the biggest change of this new version. David Hayden was trying to write a blog post with some C# code inside and in the C# code there were some attributes and there were some Shortcodes in the attributes. When you evaluate a Shortcode using this library it just outputs to nothing if it's unknown. This means all the attributes from the code were removed. From now if there is an unknown Shortcode or it can't be parsed, the module will just output it as is. AutoroutesEntries Atomicity and Size This allows for synchronization between multiple nodes of a cluster, specifically for AutoRoutes. If you are on one node and you create a new AutoRoute, then the other nodes will update their AutoRoute mapping for the new AutoRoute. It's not just about data to load, it's also updating the resolution list: a dictionary that maps content items to routes. There is an AutoRoutePartIndex that is used to detect what had changed since the synchronization of the last element. Every YesSql index is updating things with an incremental identifier so, if there is a change on one AutoRoutePart it's not updating the previous indexes, it's just adding new indexes and removing the previous one. Now, this index is used to just sync every node to the new state. It's like a synchronous pattern, the index just shows the new things that happened on the AutoRouteParts, and then it's applied directly to the AutoroutesEntries structure. Check out the AutoroutePartIndexProvider class in the dev branch! Demos Admin UI improvements The admin UI of Orchard Core got several improvements lately. In the demo of our current post, we will check out the updated UI. Let's start! When you navigate to the admin UI of your site you can see the Orchard logo and the name of your site on the left side of the top bar. From now if you click on it, it will navigate to the home page of the admin theme. But don't worry, you can still easily navigate to your site, just use the little arrow at the right of the top bar. Oh, and one more thing: if you click on that little user icon on the right, you can see the user name of the currently logged-in user. If you have the Tenants feature enabled you can add tenants to your site. The list of the tenants is now a little bit different. You can see the name of the database preset, the description, the used recipe, and the state of the tenant. Now let's navigate to the content items list to check out the new design there too. You can see that every line start with the display text of the content item, followed by the content type, the status of the content item, the date of the latest modification, and the author of the content item. You can see that the About article has a draft and a published version too. And lastly, go to the Design -> Widgets page and check out the design there. You could see we have two widgets right now, the one with the display text My widget is a content type of Container that has two versions and associated with the Homepage layer. The other one is placed on the Always layer. And that's not all of the improvements and more are just on the way! Check out this recording on YouTube to know more! News from the community Work with us! You've completed the Dojo Course, congratulations! You’re now officially an Orchard Core developer. Would you like to work on a variety of challenging Orchard Core projects with the biggest Orchard team in the world? Work with us! Just send us an e-mail to crew at lombiq.com. Please include what you’re most interested in professionally and attach around 100 lines of any kind of code that you’re especially proud of or just link to the favorite open-source project of your own on GitHub or else. Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 184 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Secrets module, Cookie based dark mode theme - This week in Orchard (10/01/2021)

We start this year by showing you the latest updates of the Dark mode of the admin UI. After that, you can read about how can expose your Lucene or SQL queries through GraphQL! Finally, we will check out the latest improvements to the Secrets module! Orchard Core updates Dark mode V2 (cookie based) A few weeks ago we mentioned that now you can use the dark mode for your admin theme. The only thing you have to do is to go to Configuration -> Settings -> Admin and check Enable dark mode admin theme. The new version of dark mode contains several improvements: Cookie based settings storage. Use only one CSS to prevent flickers and animations when switching from light to dark mode and vice versa. Use data-theme on HTML element. Fixing several modals. Fix GraphiQL styles (Codemirror global styles conflict). But what does cookie based mean? Find the DarkModeService.cs file in the OrchardCore.Themes project and check out the IsDarkModeAsync async method in it. As you can see, there is an adminPreferences cookie collection, that contains a darkMode boolean property. If it's true, that means the dark mode has been applied to the admin theme. And here comes the trick! If you check out the first few lines of the Layout.cshtml file of the admin theme, you will see that the code checks if the dark mode is currently enabled or not and puts the CurrentTheme value into the data-theme data attribute. Tutorials page in the documentation Many external resources are available in order to teach you how to develop with Orchard Core and keep you informed with the latest news and the goal of the Resources page is to give you a nice overview of these resources. Now you can find a new Tutorials page that lists some content that you can use to learn Orchard Core. Here you can find our Dojo Course 3 video series or the Orchard Core Training Demo module! Custom query schema fix and documentation Method BuildSchemaBasedFieldType inside LuceneQueryFieldTypeProvider.cs and SqlQueryFieldTypeProvider.cs was wrong because official JSON schema should look something like this: { "type": "object", "properties": { "firstName" : { "type" : "string" }, "age": { "type": "integer" } } } The line where code tries to get type specifically child["type"] will throw an error of System.InvalidOperationException: 'Cannot access child value on Newtonsoft.Json.Linq.JProperty.'. foreach (var child in properties.Children()){ var name = ((JProperty)child).Name; var nameLower = name.Replace('.', '_'); var type = child["type"].ToString();... The fix was something along the lines of and the properties key should be lowercase. foreach (JProperty child in properties.Children()){ var name = child.Name; var nameLower = name.Replace('.', '_'); var type = child.Value["type"].ToString();... You can find nice documentation here that tells you how you can expose queries through GraphQL. Demos Secrets Module We mentioned the latest updates regarding secret management back in September and now here comes the continuation of this upcoming feature. If you haven't known about it yet, you should definitely check out that post and the two recordings on YouTube. So, let's see what we are talking about exactly! The idea here is to extend some of the places that we can use to store secrets. For example, let's navigate to the Email settings (Configuration -> Settings -> Email) and say we require credentials for authentication. And of course, we need to define a user name and a password. The password is get stored with data protection. But if we export this to a production server where the data protection keys are different, the setting will no longer work and you can get an exception when you would like to use it. As you can see on the screen, the concept here is to have a secret where you select which secret you would like to use. We have already defined one called email, let's select this one. We managed that secret and the value of it under Configuration -> Secrets. Here we can select where we would like to store this secret, which can be the Database Secret Store or the Configuration Secret Store. But if you enable the Azure KeyVault Secrets Store feature, you can use the KeyVault store too. Normally when we have a form, we use an HTTP Request event to drive the form to a workflow. Let's create one Workflow, call it Form Submit and add an HTTP Request event to it. Normally what we have in the query string is a token here which is protected with data protection but we could have a little problem with it. When you use this in a Form widget and you have moved the form to a production server, it doesn't work because the token was no longer valid because it is was stored using a local data protection key. But we have a solution for that too! Here you can notice one new option called HTTP Request Event Secret. You can just simply type a preferred name to the secret and hit enter, which will create the new secret for you. Now let's create a form. If you set up your site with the Blog recipe, you can just simply enable the Forms module and create a new Page. Add the Form widget to the FlowPart where you can see the same picker that we can use to select the given secret that we would like to use. If you pick a secret, you don't need to specify the action (the URL to submit the form to) because it is stored in your HTTP request event secret and that will override the specified action value of the form. If you navigate to Configuration -> Secrets, you can check out the details of the formsubmitted secret that we have just created. The difference here is that now you have a picker here that lists all the workflows that have an HTTP Request Event as a starting activity. By using that picker you can assign this secret to another workflow if you would like to. But we are just scratching the surface of this feature and haven't talked about anything about how you can import/export your secrets using deployments plans. If you are interested in more, don't forget to check out this recording on YouTube! News from the community Our full Orchard Core tutorial series, the Dojo Course 3 is here! After a long wait, the new Orchard Core version of our legendary Dojo Course tutorial series is here, the Dojo Course 3! Are you a newcomer and want to learn Orchard Core from the ground up, both from a user's and a developer's perspective? Are you somewhat familiar with Orchard Core but would like to get up to speed and become an Orchard pro? Look no further, check out Dojo Course 3! Dojo Course 3 guides you from the very basics of Orchard Core all up to be able to write your own themes and modules, utilizing various APIs of Orchard. If you're looking for our previous Orchard 1.x tutorial series check out Dojo Course 2. Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 183 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

Admin Dashboard, Display titles in the top bar - This week in Orchard (24/12/2020)

Option to display page titles in the top bar on the admin UI, documentation for external libraries, new FileDocumentStoreAttribute, and a lot more are waiting for you in our last blog post for this year. Let's get started! Orchard Core updates Display titles in the top bar Set up your site using the Blog recipe, then navigate to the admin UI of the site. Head to Configuration -> Settings -> Admin. Here you will see a new option, called Display titles in the top bar. Let's put a tick here and see what will happen. If you save it, the titles will be placed in the top bar of the admin theme. The only thing you have to do is to slightly modify the appearance of the title of your page in the admin UI by making sure to put it in the Title zone. <zone Name="Title"><h1>@RenderTitleSegments("My page")</h1></zone> So, if you set that you would like to display the title in the top bar, then the Title section will be rendered in the top bar section of the theme, otherwise, it will stay in its own place. Hide connection string when already set for the tenant When a connection string is defined in an environment variable, the value is displayed on the Tenants creation page: $env:OrchardCore__ConnectionString="server=localhost;uid=root;database=db;password=my-secret-pw;"$env:OrchardCore__DatabaseProvider="MySql" Now if the connection string is coming from the configuration in the setup screen, then it's not displayed anymore, and this way we can't change it. The SetConfigurationShellValues method in the AdminController of the OrchardCore.Tenants module checks the values of the shell settings based on the ConnectionString and DatabaseProvider keys and if there are any, the EditTenantViewModel will get these values. And now we can only show the given sections on the front-end if these values haven't been set from the shell settings. External libraries documentation Orchard Core uses several external .NET libraries, like Jint, YesSql, and Fluid. But you can find several Client-side libraries here too, like GraphiQL, TypeScrip, React, or Vue. The goal of this new page in the Orchard Core documentation is to list all of the used libraries with their version. FileDocumentStoreAttribute providing a FileName By default, the file name is equal to the name of the related document type, e.g. ContentDefinitionRecord => ContentDefinitionRecord.json. So, for compatibility, this attribute allows keeping the current ContentDefinition.json without having to manage this specific case in FileDocumentStore with a hard-coded string. Add the email optional claim steps to AAD integration document If you follow this how-to guide, you can build a blog that allows users to login with their AzureAD account and gets assigned roles based on the Security Groups they belong to. However, the documentation hasn't mentioned yet how to set up optional claims to configure additional information when you are registering a new application (App registration) on the Azure Portal. Now this how-to has been updated with the way how you can add optional claims (like email) to your configuration. Demos Admin Dashboard To see this new feature the only thing you have to do is to just simply set up your site and navigate to the admin UI. After you will get a screen something like this. Here you can see cards, that are dashboard items, that are about to represent a piece of functionality of a given feature or module. For example, the one called Content items is coming from the Contents module and by using that, you can easily do some content-related functions (like listing the latest or the draft content item). It's pretty straightforward, so let's look under the hood to see how you can create your own dashboard items. But first, let's see how the site renders the items on the homepage of the admin UI. The AdminDashboard.cshtml in the OrchardCore.Admin module is just about to display the SummaryAdmin display type of every AdminDashboardItem that can come from any module. Let's see the first card with the title Content items. If you open up the Views folder of the OrchardCore.Contents module, you will find a view with the filename AdminDashboardItem.SummaryAdmin.cshtml. Here you can see the HTML structure of a Bootstrap card item with the custom content inside it, which in our case is some links to the AdminController in this module. We have a driver too to say display the SummaryAdmin display type and place it in a given location. That's all you have to do to have a new card on the homepage of the admin UI. This feature is under development and might be changing in the future. And it has been already changed just before we finalized this blog post. :) But what are the exact changes here? Well, that will be covered in an upcoming post, stay tuned for that! If you would like to know more about this, check out this recording on YouTube! News from the community A new website using Orchard Core: AeroSpace Cornwall AeroSpace Cornwall is a research, development and innovation fund, that enables businesses to take their idea and turn it into a viable product ready for market in the space and aerospace sectors. Check out this site to see the loads of capabilities that you can achieve using the CMS. If you are interested in more websites using Orchard and Orchard Core, don't forget to visit Show Orchard. Show Orchard is a website for showing representative Orchard CMS (and now Orchard Core) websites all around the internet. It was started by Ryan Drew Burnett, but since he doesn't work with Orchard anymore, as announced earlier it is now maintained by our team at Lombiq Technologies. Our full Orchard Core tutorial series, the Dojo Course 3 is here! After a long wait, the new Orchard Core version of our legendary Dojo Course tutorial series is here, the Dojo Course 3! Are you a newcomer and want to learn Orchard Core from the ground up, both from a user's and a developer's perspective? Are you somewhat familiar with Orchard Core but would like to get up to speed and become an Orchard pro? Look no further, check out Dojo Course 3! Dojo Course 3 guides you from the very basics of Orchard Core all up to be able to write your own themes and modules, utilizing various APIs of Orchard. We're publishing a tutorial video every day for 40 days starting on 1 December. So, this is your 40 days of Orchard :). Videos about Orchard Core development are on the way, you can see a new one every day! If you are really interested in the coding part, the upcoming, almost 20 videos are specially for you. If you're looking for our previous Orchard 1.x tutorial series check out Dojo Course 2. Christmas in Lombiq Sometimes we do stuff. Together. Not (just) in front of computer screens. These are some usual events in Lombiq that are all announced and arranged in advance. We periodically have an event called RnDay: this is a few hours long event where we share with each other what we recently worked on and what we plan to do. E.g. if we recently finished a project then the project's team members demo what they've done. Last week we had our last RnDay for this year but this time we have to make it online. We also named this event to The 13th RnDay - Pandemic Edition! We also tried to do our best to make a nice group photo, you can see the result down below. :) We would like to thank you all for reading our posts and making the Orchard community stronger together with us! We hope that we could give you valuable news and demos about the happenings around Orchard and Orchard Core from time to time by reading our posts and of course the This week in Orchard newsletter. We would like to wish everyone a Merry Christmas and a Happy New Year! See you next year! Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 178 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!

User Picker Field, the new user ID - This week in Orchard (06/12/2020)

This time we will do a little deep dive and check out some important changes in the code base of Orchard Core. But don't be scared, we promise you will like these changes, especially the demo about the new User Picker Field! Orchard Core updates Allow media width and height values without a token You could see a demo a few weeks ago in this post about the new options for Media Field where you can set the alt text of your image and you can also crop your images using a nice media crop picker. The way it was working is it's putting different kinds of options to the query string that allows you to manipulate your image. Let's see the following URL for an example: https://localhost:44300/media/post-bg.jpg?width=1&height=600&rmode=crop&rxy=0.2,0.5. Here you can see we set the width and height of the image from the media library. We also set the resize mode for the processed image with other parameters as well. A few days later the community introduced a new bool option added to the MediaOptions called UseTokenizedQueryString to encrypt the image processing query string to prevent disc filling, that is true by default. And now here comes another great stuff that allows values for width and height to be provided via the query string even when tokens are enabled. What does it mean? Let's see an example of it! Set up your site using the Blog recipe then open the default banner image URL of the predefined blog post with the following query string parameters: https://localhost:44300/media/post-bg.jpg?width=1024&height=600. Note that the tokens are enabled by default, but you can still set the width and the height of the image now. Don't forget that this will only work if the height and width values match the supported sizes array values. Introduce Culture Scope There is a new CultureScope class that you can use if you want to locally set the current culture (the current user interface culture and the culture used by the current thread). You can find several unit tests to see how you can use it, but check out this one for now. Here you can see that the culture is set to French, but that setting only applies inside the using statement. Implement UserId All the user profiles that you have locally, now have a new property called UserId, which is unique. We used to use a name, the user name as the way to identify a user. But now the community decided to use a unique ID such that you can't guess user ID or you can't recover another set or permission or ownership by mistake, because an account has been deleted and someone created a new account using the old name and somehow the logical references are still kept based on this name and you would inherit something from that. So, to prevent that, Orchard Core is using now a user ID. If you take the latest version of the dev branch and just run your code there will be a migration that copies the user names of the existing users as the user ID. This way you don't have any change in your content, it will still work the same and be careful that your user ID equals a string like 4gq8jagmrtxrwvg21csa0b6y4y, which is safe, because the next time someone creates a new user, they can't impersonate anyone else like recovering an old account, because it will be a newly generated unique identifier that can't match something like that. And how can you find the currently logged in user? Check out the code in the DefaultContentsAdminListFilter where you can see that now, instead of using the user.Identity.Name, you can use the FindFirstValue extension method from ASP.NET Core to return the value of the first instance of the specified claim type, or null if the claim is not present. And then you can set that value as the Owner of the content item. Demos User Picker Field Let's say you would like to create a blog where multiple users can create blog posts and you want to connect the user account of the author user with the given blog post by showing the name of the user somewhere in the detail view of the post. It's easy because the users can log in to the admin UI of Orchard Core and publish their own posts. In this case, they will be the authors of the given content items. But let's say we don't want to give them access to the site. We just want them to send the content of the blog post to a given email address and the site editors will edit and publish the posts. Is there an easy way to connect content with user accounts in Orchard Core? Set up your site using the Blog recipe. This recipe comes with a predefined blog where you can create new blog posts. The posts can have several properties: the title, the banner image, tags, the category, and so on. We will modify the content definition of the Blog Post to do some tricks. Navigate to the admin UI of Orchard Core and head to Content -> Content Definition -> Content Types and edit the Blog Post one. Click on the Add Field button and find the recently added one, called User Picker Field. This field allows you to connect users with a content item. Here you can say that you want to allow multiple users to be selected, allow the picker to display users from all roles, and many more. If you put a tick on the Display All Users checkbox, every user will be in the list that you can choose from, if you remove the tick, the available roles in the system will be listed and you can choose from them. Now if you edit the predefined blog post, you will see the User Picker Field in action. In this case, we have two users in the system named admin and editor. The admin is the superuser with the Administrator role and the editor user has the Editor role. We can see both of them because we said we would like to allow the picker to display users from all roles. If you save your content item, the field will show you the user names of the selected users seperated by a comma (if you selected multiple ones). And you will see a No users. message is you haven't selected any users. You can find some lines about the User Picker Field in the documentation of Orchard Core and a nice presentation of this feature on YouTube! News from the community Our full Orchard Core tutorial series, the Dojo Course 3 is here! After a long wait, the new Orchard Core version of our legendary Dojo Course tutorial series is here, the Dojo Course 3! Are you a newcomer and want to learn Orchard Core from the ground up, both from a user's and a developer's perspective? Are you somewhat familiar with Orchard Core but would like to get up to speed and become an Orchard pro? Look no further, check out Dojo Course 3! Dojo Course 3 guides you from the very basics of Orchard Core all up to be able to write your own themes and modules, utilizing various APIs of Orchard. We're publishing a tutorial video every day for 40 days starting on 1 December. So, this is your 40 days of Orchard :). In the first few videos, we gave you an introduction to Orchard Core and showed you a way about how to set up your first Orchard Core website. After we started to talk about the content model of Orchard Core, checking out the basics of content management. We will stay in the admin UI for a little in the upcoming days and check out the other basic features of the CMS like how to add widgets with layers, managing the menus, and the media files. After we will see how can you search and index content items, and build forms using the Forms and Workflows feature. But we will not spoil the topics of the upcoming videos. :) If you're looking for our previous Orchard 1.x tutorial series check out Dojo Course 2. Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 172 subscribers! We have started this newsletter to inform the community around Orchard with the latest news about the platform. By subscribing to this newsletter, you will get an e-mail whenever a new post published to Orchard Dojo, including This week in Orchard of course. Do you know of other Orchard enthusiasts who you think would like to read our weekly articles? Tell them to subscribe here! If you are interested in more news around Orchard and the details of the topics above, don't forget to check out the recording of this week's Orchard meeting!