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

Centralize the Indexing process, Remove Media files for a removed tenant when using Azure Blob Storage - This week in Orchard (20/06/2025)

This time, you can see a demo about centralizing the Indexing process and having a unified UI for managing Indexes and the Search Settings! But first, let's look at our other topics, like removing Media files for a removed tenant when using Azure Blob Storage, and adding RouteEndpoint cache. Don't forget that you can still fill out our Orchard Core Admin UI experience renewal survey to help shape the future of Orchard Core!

Latest tutorials

Featured tags

IIS
API
SMS
SEO
MCP
All tags >

Application Insights Module, HeadMeta zone alternate - This week in Orchard (11/04/2021)

The Application Insight module is now available for Orchard Core too! Check out our current post for tons of updates like the new HeadMeta zone alternate, the now() helper function in SQL Queries and many more! Orchard Core updates Support for now() helper function in SQL Queries If you do a query like this in the generic SQL language we support, this will be mapped to whatever database are you using. As you can see, if you are using the new now() helper function, you can get the current date and time. Check out the where condition of the query below: where the PublishedUtc value of the published BlogPost content types is bigger than the current date and time. Add HeadMeta zone alternate for layer widget wrapper When rendering resources using Layers in the HeadMeta zone the widget wrapper is applied, which makes for illegal HTML code inside the <head> of the webpage. Of course, you can render resources in the Content zone, but then you just end up with an empty widget wrapper. Which also makes no sense. The solution is to in the list of layer zones, also include a list of Zones which do not wrap with the widget wrapper. This is useful for other scenarios where the extra divs added by the widget wrapper are not wanted. Here you can see the two now Liquid templates for the Agency and the Blog theme, and the Razor one for the default TheTheme. Fix migrations from RC2 to the latest dev Dean Marcussen did some tests to validate that we can migrate easily without any issue from the RC2 release to the 1.0 release. The idea being is if you are using the RC2 release of Orchard Core and you want to migrate to 1.0, then there won't be any exception or database conflicts or whatever. This mainly means new or updated migration steps for the modules, or move something to a feature, or the migration dependencies are not ordered correctly. BackgroundTask Atomicity You could see a demo in this This week in Orchard post about workflows atomicity. Now here comes a continuation of that feature, the BackgroundTask Atomicity. In a nutshell, it means some additional settings like: Configurable per IBackgroundTask through a LockTimeout and an auto LockExpiration in milliseconds, by default, there are equal to 0 and in that case, it works as before without any locking. Configurable by code through the background task attribute. Or through the admin UI by enabling the existing OrchardCore.BackgroundTasks feature. Right now we have just implemented the IBackgroundTask interface and navigated to Configuration -> Tasks -> Background Tasks and hit the Edit button near the new background task that appears in the list. And in the Advanced tab of that background task, you can set the lock timeout and lock expiration values. Note that you need to enable the BackgroundTasks feature. Arrows for collapsible panels It's a minor change but fixes like this one make the admin UI of Orchard Core more consistent for the users who can access the admin panel. We have different collapsible panels in Orchard Core and the arrows were not consistent in any cases. Now, if you have a Bag Part attached to your content item, the arrow near the collapsible section will be directed to the right by default. And if you open that section, the arrow will be head to down. So now we use the same kind of arrows (Right if collapsed, Down if expanded) for all collapsible panels in the admin. And this also supports Arabic and RTL languages, where we need to direct the arrow left if the panel is closed. Demos Azure Application Insights module This Lombiq Hosting - Azure Application Insights Orchard Core module 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. Application Insights is an application performance monitoring tool. Withing Azure you can create such Application Insight resources and it will give you nice metrics and other data about your app that is running or production or staging or something. This is not for local but rather for seeing what happens in an application that is actually deployed somewhere. The Readme.md file in the repository shows you how you can set up the module and do the basic configuration just by editing your appsettings.json file. Let's say we have a site installed with the Blog recipe. If you add the module to your solution and enable it (Configuration -> Features -> Lombiq Hosting - Azure Application Insights) you can go to the configured corresponding Application Insights account and for example, check out the live metrics. Or you can see what happened in a given request. You can see all the details correlated: the request, the page views, the dependency calls, everything. For example, you can see that there was a server-side request. The Item/Display action was called which actually returned you the content item that is the homepage. It happened on the development environment on the Default shell with the user named admin. If you would like to know more about this module, don't forget to head to the repository of the module and try out it now! And as always, here is a recording that you can check out anytime! News from the community Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 194 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!

SEO Module, Drag and Drop Dashboard Widgets - This week in Orchard (04/04/2021)

A huge new module has been added to Orchard Core; the SEO Module! Let us write some lines about this module and the added drag and drop capabilities to the Dashboard Widgets. Check out our post for more! Orchard Core updates Rule Benchmark A few weeks ago you could see a demo about the Rules module, which allows you to build rules for the layers without using JavaScript. If you remember we mentioned that if you use the Rules module instead of JavaScript, the performance of the layers is much better. And now we can prove that we are right! If you open up the RuleBenchmark.cs file in the OrchardCore.Benchmarks project you can see some comments with exact numbers. The EvaluateIsHomepageWithJavascript is the one that uses JavaScript to evaluate the rule that is about the check if the currently opened page is the homepage or not. And the EvaluateIsHomepageWithRule is the same, but this time we did that with the Rules module. The first table showing you the results when you are using .NET Core 3.1 and the second table is showing you the results when you are using .NET 5. As you can see, there is not much difference between the two EvaluateIsHomepageWithJavascript methods (.NET 5 is a little slower but we can safely say that it's the same), but if you are using the Rules module and .NET 5, you will get the best performance at all. But the goal here is not to optimize Orchard Core for .NET, it's about showing the fact that if you are using the Rules module instead of the JavaScript expression, you can get better rule evaluations on your site. Add fieldTypeName to Query Schema for GraphQL If you create a query and you want to expose it as a GraphQL, you can create a custom GraphQL schema to define the metadata such that clients know what they can query. And now there is a custom property called Name that will contain the name of the query itself. Such that when we use GraphQL to do to run some dynamic queries like SQL queries or Lucene queries we can now access them through a custom name and not the generic name, which is the name of the query in the system. Because there could be conflicts between different query providers in GraphQL. For instance, the default name we use for Lucene and SQL queries is the custom name we pass. For the content types, we also use the name of the content type. So, if you have a query that has the same name as the content type then GraphQL won't know what to query. The content type or the custom query? So, by using this custom Name property, you can add a custom name if there is a conflict. You can read more about queries in the docs. Demos Resize, Drag and Drop Dashboard Widgets You could see and read about a great feature of Orchard Core a few weeks ago that is about to add cards to the homepage of the dashboard, which is about to represent a piece of functionality of a given feature or module. In the meantime, several other great features had been added to the Admin Dashboard feature, so, let's check out them quickly! The first thing you have to do is to go to Configuration -> Features and enable the Admin Dashboard feature. And now just simply need to navigate back to the homepage of your admin UI to see the admin dashboard that has just changed because of the newly enabled feature. You can see one predefined card here with the title Orchard Core, and the HTML Body of that widget. This content item has the Html Dashboard Widget content type and the DashboardWidget as the stereotype. Don't forget that if you would like your content type to act as a dashboard widget, you have to set the stereotype to DashboardWidget. So, back to the admin homepage. At the top-right of your screen, you will see a Manage Dashboard button. By hitting that button you will have the option to edit, delete or add new widgets to your dashboard. Every dashboard widget has a DashboardPart attached by default that contains three properties: Position, Width, and Height. These can be used to set the size and the position of the given widget. But from now you can also use drag and drop to move or resize your widget. The best way to represent the improvements of the dashboard widgets is a GIF that shows you how you can use the improved UI. And as always, if you would like to know more about Dashboard Widgets, head to YouTube for a recording! SEO Module Buzz Interactive developed a SEO module for Orchard Core and thanks to Dean Marcussen (who is working at this company) offered that the module can be integrated into Orchard Core as a contribution. And Antoine Griffard already did the integration. A huge thanks to them! Let's see this module in action! Set up your site using the Blog recipe, then head to the admin UI. Find Configuration -> Features where you will see the new module that you need to enable, called Seo, that provides SEO Meta features. If you enable it you are able to use an SEOMetaPart that you can attach to the content types that you want to be able to support SEO features. Let's attach this one to the Article content type for example. Now let's open the predefined About Article content item to see what's changed in the editor. The first thing that you may notice that now there is a new SEO tab that you can use to set up those SEO options that are specific only for this content item, like the page title, meta description, canonical URL, meta robots, and so on. But before doing more digging here let's go back to the modified content definition of the Article content type (Content -> Content Definition -> Content Types -> Article) and hit Edit near the SeoMeta part. Here you can see some additional editor settings. You can select that if you want to display the keywords or not, display the Open Graph or not, and so on. So, if you check all of these and navigate back to edit the Article content item, the SEO tab now will have more cards. You can easily open or collapse each of these cards and you can set the relevant settings under the given card. For example, if you collapse the Twitter one you can set the SEO settings related to Twitter. You may notice the little [/] icon in every editor of the SEO tab. That means you can inject Shortcodes to these input fields. Let's just add a simple [display_text] Shortcode to the site (you can see the values that you will need here) and use that in some places just for an example. Now to check how SEO works, navigate to the front end of your site and open our About article. If you view the page source, you will see the meta tags in the head of your site. If you would like to know more about this module, don't forget to check out this recording on YouTube! News from the community 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!

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!