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 >

Distributed cache, YesSql improvements - This week in Orchard (09/10/2020)

Get ready for the upcoming additions of Orchard Core! This week you can see demos about adding distributed cache to Orchard Core and the latest improvements of YesSql! Orchard Core updates Restrict Content Types Admin Node to only create the specified content type Let's say you have a site set up with the Blog recipe and your goal is to add a new admin menu that is about to list all the existing Article content items. To do that you have to navigate to Configuration -> Admin Menu and click on the Add Node button. Here you will need to select the Content Types Admin Node because you would like to add a link for each one of the selected content types from the list. And yes, you will only select the Article content type in the next screen. And that's it, you have created a new admin menu that lists all of the Article content items from the system. If you click on that you will see the list of the Article content items. Note that from now you will not see a filter here to filter by content types because that really doesn't make much sense. You created this Content Types Admin Node to list only the Article content items. If you would like to filter by content type, use the filter in the Content -> Content Items page as you would do it before. Remove ManageOwnMedia permission The ManageOwnMedia permission isn't handled today and we can replace it with the ManageMedia permission. So, now there is no separate permission to manage their own media or manage the media. It will be added back to the system again if the authorization logic is to be able to separate the user's media and the media uploaded by others. Right now, if you head to Security -> Roles and hit the Edit button near one of the Roles, you will see the missing Manage Own Media permission. Use a dropdown menu on the admin top navbar for the user menu The user menu on the admin theme is just about listing the user name of the currently logged-in user with a little icon near it. And there was a Log off link at the right side of the user name. It was just a piece of HTML code in the Layout.cshtml file of the default admin theme. From now the whole user menu gets its own shape, called UserMenu.cshtml. If you would like to override the user menu, you don't need to create a Layout.cshtml file in your admin theme, you just need to override the UserMenu.cshtml file. And if you check out this GIF, you will see that now the content of the user menu is placed in a dropdown instead of having it's content inline. Document release procedure Orchard Core is open-source that means you can check out and request changes to the source code, tell your opinion about it, and update the relevant documentation for that piece of code. Now there is a new page in the Orchard Core Documentation about how to publish a new Orchard Core release. These notes are primarily for Orchard's core contributors to guide them on how to prepare a new release, but if you just take a look at these you can now see what are the steps that need to be done to be able to ship a new release of Orchard Core. Add option to allow Lucene query syntax in the search There is a setting in the Lucene module that you can turn on and whatever you type in the search box won't be parsed as 'these are the words that I need to search on', but parsed as this is a Lucene query. You can use the Lucene query syntax in search forms, like the quotes, plus signs and things like this. But by default, it will still be like today, which is type words and it looks for these words. If you type stuff that has weird characters, they would be ignored. But how can I turn on that feature? Just navigate to the admin UI of Orchard Core, then find the settings in Search -> Settings -> Search (make sure you have enabled the Lucene module). Demos YesSql: Adding support for multi filters on the same table index There is a new method on .IQuery called .Or(), which starts a filter on a distinct table. This can be used for instance when the same index needs to be queried for multiple sets. It will actually add many filters on the same record of the index. With .Or() you can do now filters on different inner joins of the same index. Which means it will do unions of result with the filters. Let's check out the following unit test. [Fact]public async Task ShouldQueryMultipleIndexes(){ // We should be able to query documents on multiple rows in an index. // This mean the same Index table needs to be JOINed. _store.RegisterIndexes<PersonIdentitiesIndexProvider>(); using (var session = _store.CreateSession()) { var hanselman = new Person { Firstname = "Scott", Lastname = "Hanselman" }; var guthrie = new Person { Firstname = "Scott", Lastname = "Guthrie" }; session.Save(hanselman); session.Save(guthrie); } using (var session = _store.CreateSession()) { Assert.Equal(2, await session.Query<Person>() .With<PersonIdentity>(x => x.Identity == "Hanselman") .Or() .With<PersonIdentity>(x => x.Identity == "Guthrie")) .CountAsync()); }} This PersonIdentitiesIndexProvider will just map the first name and the last name of each person. We created two persons here that means the provider will be creating four PersonIdentity records. Two to store the first name and last name for Scott Hanselman and two to store the first name and the last name of Scott Guthrie. If without using the .Or() it will issue a query where the Identity == "Hanselman" AND Identity == "Guthrie", which will return nothing. With the .Or(), it will do an inner join on PersonIdentity with a filter on Identity == "Hanselman" and another inner join on PersonIdentity with a filter on Identity == "Guthrie". In this case, we will get both the two persons. It's like give me any person who's PersonIdentity has a record like Hanselman OR where the PersonIdentity equals Guthrie. Let's see another example! // Creating articles.using (var session = store.CreateSession()){ session.Save(new Article { Content = "This is a green fox" }); session.Save(new Article { Content = "This is a yellow cat" }); session.Save(new Article { Content = "This is a pink elephant" }); session.Save(new Article { Content = "This is a green tiger" });}using (var session = store.CreateSession()){ Console.WriteLine("Boolean query: 'pink or tiger'"); var boolQuery = await session.Query<Article>() .Where(x => x.Word.IsIn(new[] { "pink" })) .Or() .Where(x => x.Word.IsIn(new[] { "tiger" })) .ListAsync();} This is a full-text sample where in this case we can query documents by their content, by their words. If we have the documents as you could see in the code, we are creating an index for all the words pointing to the document, like green and fox points to the first Article. Now the query is about to give me all the documents that have pink in it OR all the documents that have tiger in it. The goal is to get the last two articles in this case. Let's check out this query: var boolQuery = await session.Query<Article, ArticleByWord>().Where(a => a.Word.IsIn(new[] { "white", "fox", "pink" })).ListAsync(); This query will return all the articles that have white AND fox AND pink in it and there is none in this case. You can find the recording of this improvement on YouTube! But wait a minute! Could this syntax be better? When you have a query, you can say .Any() and every predicate will be done in a different table. .Any() being an OR, and .All() being an AND. In this case, we're querying on the same index (ArticleByWord) but each of the calls on .With() will be a different projection, a different inner join in this case. Here we are looking for an article that has the word pink OR the words green AND fox. await session.Query<Article>() .Any( x => x.With<ArticleByWord>(a => a.Word == "pink"), x => x.All( x => x.With<ArticleByWord>(a => a.Word == "green"), x => x.With<ArticleByWord>(a => a.Word == "fox"))).ListAsync(); SELECT DISTINCT Document.* FROM DocumentINNER JOIN ArticleByWord_Document AS [ArticleByWord_Document_a1] ON ArticleByWord_Document_a1.DocumentId = Document.IdINNER JOIN ArticleByWord AS [ArticleByWord_a1] ON [ArticleByWord_a1].Id = ArticleByWord_Document_a1.ArticleByWordIdINNER JOIN ArticleByWord_Document AS [ArticleByWord_Document_a2] ON ArticleByWord_Document_a2.DocumentId = Document.IdINNER JOIN ArticleByWord AS [ArticleByWord_a2] ON [ArticleByWord_a2].Id = ArticleByWord_Document_a2.ArticleByWordIdINNER JOIN ArticleByWord_Document AS [ArticleByWord_Document_a3] ON ArticleByWord_Document_a3.DocumentId = Document.IdINNER JOIN ArticleByWord AS [ArticleByWord_a3] ON [ArticleByWord_a3].Id = ArticleByWord_Document_a3.ArticleByWordIdWHERE ArticleByWord_a1.Word = 'pink' OR ( ArticleByWord_a2.Word = 'green' AND ArticleByWord_a3.Word = 'fox') Here you can also see how does the query look like. That's the current syntax right now. And it's not breaking change because if you had .query.With().With(), it will still behave the same as before. It will be a single projection with two .With(). If you project on the same table it will be an AND on the same table, the same projection.If you would like to know more about the current syntax and the latest features, this is the YouTube video that you are looking for! Distributed Redis Cache There is a huge PR with a great addition to Orchard Core about having Distributed Cache in Orchard Core. In fact, this PR is related to all modules services using cached data that need to be in sync with a shared database, e.g. site settings and other admin settings, templates, queries, layers, and so on. Currently, in the dev branch, this is already the case for most of them but by using local memory cache entries that are invalidated through a distributed signal. This PR has changed this pattern by using a multi-level cache including a distributed cache. And Jean-Thierry Kéchichian made more services to be distributed aware, there are remaining things but could be done in other PRs. And recently he added the ability through a separate feature to also keep in sync tenant states, when you enable/disable/create/setup a tenant. To summarize: All services that were using the memory cache are now using a multi-level cache including a distributed cache, this cache is kept in sync with the database without using a message bus but document identifiers. We have concrete implementations of distributed services based on Redis, Redis cache, Redis data protection, Redis message bus, and Redis lock. In the current code, we never use a message bus/distributed lock. When enabling a concrete distributed cache in the default tenant, we automatically keep all tenants in sync through a hosted service, here also without using a message bus but identifiers. Here a stateless configuration is needed. There is a separate feature (DefaultTenantOnly) to keep tenants in sync. Don't forget to head to YouTube and watch the recording of this upcoming feature! News from the community Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 160 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!

New custom filters in Fluid, Media options admin page - This week in Orchard (02/10/2020)

We prepared two interesting demos for this week: The first one is about having new useful custom filters in Liquid to make formatting numbers and string easier. The other upcoming feature is about how you can show your settings from your appsettings.json files without having the need to open these files in your file system. Orchard Core updates Restrict Content Type Admin Menus to only create the specified Content Type Several issues fixed regarding creating content items from the admin UI: Restored the new button specific to each content item when user filters by content type or accesses the content item list interface by link for a single content type in the admin menu. Fixed the behavior of the admin menu's links to Menus and Content Items: if they are not defined inside a recipe, they have a dynamic behavior and it causes an issue if the user defines a link for a specific content type inside the admin menu. In the BlogTheme, the Content Items link of the admin menu is defined in the recipe and doesn't have dynamic behavior. See the following GIF here where you can also see the creation of a new content type admin menu node that is about to list the Article content items. The new button under the new Article menu option is just about to create new Article content items. Update Blob Storage to search folder hierarchies The problem is that the method that is responsible to handle Blob Storage items does not correctly implement the includeSubDirectories = true option - it never did. This is because it's not like a normal file system where you can make one request and list everything, so it would have to make recursive requests for every directory it finds. Ironically the media step driver does this recursion already itself, but the recipe step does not when using Include All Media. So the short term workaround should be to specify the attached fields' folder's media fields, rather than Include All Media when creating the step. This issue withincludeSubDirectories = true affects this step, and the GraphQL media query - it's the only place we use it. So, Blob storage never handled searching subfolders correctly, so this should now work for the media step, and better in GraphQL queries (behaves identically to normal file system now). Now if you would like to get the content of the directory including subfolders too, the GetDirectoryContentFlatAsync method in the BlobFileStore class will return the files inside the subfolders too. Rename Smtp admin menu to Email The goal of renaming Smtp to Email is to make sure that you can edit settings related to sending emails even if you don't know what SMTP is (and this screen is also for testing email sending). Toggle password visibility on the login form and on the setup screen The login form and the setup screen now support toggling the password visibility, so can make sure that you typed the correct passwords in these textboxes. Demos Media options admin page In the appsettings.json file, you can define your media-related settings, e.g. change the list of allowed file extensions or the path used when serving media assets. The documentation includes all the default configuration values that can be overridden. The goal of this feature is to have a read-only version of the settings where you can see these configuration values without needing to navigate to your appsettings.json file to see the configured values. Head to YouTube to check out this short recording about this upcoming feature! New custom filters in Fluid Fluid is an open-source .NET templating engine that is as close as possible to the Liquid template language. It's a secure template language that is also very accessible for non-programmer audiences. It also contains an ASP.NET Core MVC View Engine. And of course, Orchard Core is using Fluid too to generate templates. If you would like to render numbers correctly, Fluid just renders them in a format 124456789, but you could not format it like for example 12,445.68 )(and you can't do it in Liquid by default either). We already had the format_date helper in Fluid where we can use the .NET formats, so the new helpers added are format_number and format_string, which are using the .NET format methods. They are not standard in Liquid, but there is nothing in Liquid to help achieving these. format_number: It will format the number with the current culture. If you pass "N", which means number in the standard numeric format strings, then it will use the number format that we have just mentioned above. So, to generate 12,445.68 from the 12445.6789 value, you can do that like 12445.6789 | format_number: "N" You can find a documentation about the standard numeric format strings here. format_string: In this case, you can pass a string with a String.Format inside and after using the format_string you can pass the values. Let's say you have the following expression: "hello {0} {1:C}" | format_string: "world" 123. This would be rendered as hello world $123.00. Notice that here we also used the currency ("C") format specifier to convert a number to a string that represents a currency amount. The documentation of Fluid contains the available custom filters where you can learn more about the other features of Fluid too. Head to YouTube to check out the recording about the new custom filters! News from the community Orchard Dojo Newsletter Lombiq's Orchard Dojo Newsletter has 161 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 disabled/enabled events, filter admin menu - This week in Orchard (07/02/2020)

Orchard Core has got several new features and fixes this week! With many others, we will see the new user disabled/enabled events, the new IAreaControllerRouteMapper implementation, the way how you can filter the admin menu then show you a demo about how to integrate stripe.js in your Orchard Core application with workflows. And finally, say some words about a new tentative date and location for the upcoming Harvest! Orchard Core updates Reduce the length of indexes for Content Fields Indexing Let's focus on the LinkFieldIndex and check these two columns: the Url and the BigUrl. The Url is the one that is trimmed and indexed, and the BigUrl is the original data that is not indexed. If you are using MySQL, the maximum length that this provider can support in an index under UTF8 collection is 768. Now we set the maximum length of the indexed columns is to not be longer than the supported length. Do not check "Include all content types" in deployment step by default When you create a content type deployment step, the default is to export all types. Now, this is unchecked by default. Adding User Disabled/Enabled Events The IUserCreatedEventHandler is changed to IUserEventHandler and there are two new events: DisabledAsync and EnabledAsync events. These two new events now triggered in the UserDisplayDriver that will trigger the two newly created workflow events to make it work in your workflows. Adding IAreaControllerRouteMapper Now there is an updated way how the admin prefix is applied by using custom convention and constraint that will ensure that the admin URLs start with the admin prefix. And also ensure that it is done correctly for the controllers that are named AdminController, not the ones that start with admin. Before every controller that starts with admin could be an admin controller, but now with this new convention, it has been decided that only controllers named AdminController can be an admin controller. For example, a controller named AdminItemController doesn't fall into this category, so it can't be an admin controller. A concrete implementation being AdminAreaControllerRouteMapper that uses AdminOptions to provide a default route pattern that is used in the OrchardCore.MVC startup. Just as a reminder, if you have admin controllers you have to name them AdminController or have the Admin attribute on that. This will ensure that the URL is strictly using the admin prefix (or whatever you set it), and the user has the admin permission and this will also apply the admin theme to the views from this controller. Filter admin menu Head to Configuration -> Settings -> Admin and put a tick near the Enable Admin Menu filter checkbox. Now you will have a new textbox at the top of the admin menu with a Filter placeholder text inside it. If you type something here you can filter the menu items and could find easier the option you want. And if you hit CTRL+SHIFT+F, this textbox will get the focus and you can type the menu option that you are looking for without needing to click into this textbox. Add menus content listing and create option If you navigate to the Content option of the admin menu you will find a new one, called Menus. This feature is listing all the menus of the system, and if you can see, there is a new button, called New Menu. By clicking on this button you can create a new Menu without needed the Menu content type to be creatable. Make lists sortable with ordering setting A few weeks ago we write about a way how you can make sortable lists using the Enable Ordering setting of the ListPart and you can also find a demo on YouTube about this feature. The good news is this feature is now merged to the dev branch of Orchard Core! Checkout to the latest changeset of the dev branch and try this feature now. Then don't forget to tell your opinion about it in the comments section! Razor Helpers documentation Now there is a new page in the Orchard Core documentation that contains the extension methods that are available in Razor using @Orchard. This documentation also contains the way how to use an extension method in a view and in a controller too. Demos Stripe.js and Workflows You can use Stripe.js’ APIs to tokenize customer information, collect sensitive card data using customizable Stripe Elements, and accept payments with browser payment APIs like Apple Pay and the Payment Request API. And of course, you can add Stripe.js to your Orchard Core site too! Let's create a registration form where users can register and after successful registration, they can pay the fee for a ticket. After the user submits the form, here comes a huge workflow, that will validate all the fields of the form. Here you can see the several validations, and when there is no error, the workflow will send an email, create an Enrollment in Orchard Core and redirect the user to stripe using a Fork. And there will be another workflow that will validate the payment using the response that Orchard Core will get from stripe.js. Now let's take a closer look at the Create Content Task that creates a new Enrollment content type. When you are creating a new content type using this task, you have to write the properties of the content. This is the JSON that is used to construct the given content item. As you can see, here you can use different Liquid expressions as well, for example, we could use the data coming from the form. You can see the website using this registration form under this URL. Here just click on the Register at the top right and select from the listed options. If you would like to see the whole demo just head to YouTube and watch the recording! News from the community A new tentative date and location for the next Harvest We have another tentative date for the next Harvest: the last week of June. In this date, we could do it in Europe and in a location that is easier to go from the USA too. London and Amsterdam have airports that can be reached easily from several other countries as well. What do you think about the new date and locations? Orchard Dojo Newsletter Now we have 114 subscribers of the Lombiq's Orchard Dojo Newsletter! 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!

This week in Orchard - 12/27/2019

New deployment step for Open ID Server, a new multi-tenant platform built with Orchard Core and a very interesting demo about a custom admin tree module with taxonomy terms menu are waiting for you among other exciting news in this year's last This week in Orchard post! On Orchard Core Allow replacing a Liquid filter Orchard Core has several built-in Liquid filters. You can make your own Liquid filter if you implement the ILiquidFilter interface. However, it could be a valid use case if you would like to change the behavior of one of the predefined built-in filters and replace it with your own one. When registering a Liquid Filter to the service container, you have to do it in the ConfigureServices method of your Startup.cs file: public override void ConfigureServices(IServiceCollection services){ services.AddLiquidFilter<BuildDisplayFilter>("shape_build_display"); services.AddLiquidFilter<ContentItemFilter>("content_item_id");} Here you can see how to register the shape_build_display and content_item_id filters. But let's have a closer look at that AddLiquidFilter extension method! public static IServiceCollection AddLiquidFilter<T>(this IServiceCollection services, string name) where T : class, ILiquidFilter{ services.Configure<LiquidOptions>(options => options.FilterRegistrations.Add(name, typeof(T))); services.AddScoped<T>(); return services;} You could see that every time when you call AddLiquidFilter it adds your filter to the FilterRegistrations Dictionary. To be able to override an existing Liquid filter with your own, Jean-Thierry Kéchichian had to change this extension method a little bit and instead of adding the new filter to this Dictionary, just overwrite an existing one. public static IServiceCollection AddLiquidFilter<T>(this IServiceCollection services, string name) where T : class, ILiquidFilter{ services.Configure<LiquidOptions>(options => options.FilterRegistrations[name] = typeof(T)); services.AddScoped<T>(); return services;} Delete role should warn the user if the role has associated users Let's create a custom role and let's name it Blogger. Now let's create a new user and add the Blogger role to it. Now go back to the Roles page and delete the Blogger role. If you hit the Delete button you will see a warning message, that says this role is associated to existing user(s). Prefix resource manager definitions for sample themes When you would like to register your resource using the ResourceManifest, you have to do something similar: manifest .DefineScript("vendor-bootstrap") .SetDependencies("vendor-jQuery") .SetUrl("~/TheBlogTheme/vendor/bootstrap/js/bootstrap.min.js", "~/TheBlogTheme/vendor/bootstrap/js/bootstrap.js") .SetCdn("https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js", "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.js") .SetCdnIntegrity("sha384-JjSmVgy...", "sha384-rkSXwmdF/9eRLkw/gNZG+1...") .SetVersion("4.3.1"); But what if you want to register Bootstrap again in your custom theme? You can do that of course, but when there are multiple resources with the same name, the resource manager takes the one with the highest version. // Use the highest version of all matchesif (resource == null || (resourceDefinition.Version != null && new Version(resource.Version) < version)){ resource = resourceDefinition;} To make things easier every predefined resource in the themes available in Orchard Core now has prefixes, which is the name of the theme. As you can see in the following code snippet, we registered the script for Bootstrap in the Blog theme with the name: TheBlogTheme-vendor-bootstrap. manifest .DefineScript("TheBlogTheme-vendor-bootstrap") .SetDependencies("TheBlogTheme-vendor-jQuery") .SetUrl("~/TheBlogTheme/vendor/bootstrap/js/bootstrap.min.js", "~/TheBlogTheme/vendor/bootstrap/js/bootstrap.js") .SetCdn("https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js", "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.js") .SetCdnIntegrity("sha384-JjSmV6OrQ6VrjIEaF...", "sha384-rkSGcqMuXXwmdF/9eRLkw/gNZG+1zYut...") .SetVersion("4.3.1"); Deployment step for Open ID Server Head to Configuration -> Features and enable the OpenID Authorization Server module. Then you will get a new OpenID Connect option under the Security menu, where you can set up the authorization server, application, and scopes. If you set up the server in a way (the way how it's not important right now) you can import the settings of your server if you create a new deployment plan under Configuration -> Import/Export -> Deployment Plans. If you select the OpenID Server step, that will export all the Open ID Server settings. Just execute the deployment plan locally. After if you open the Recipe.json file in the zip you will find a section called OpenIdServer in the steps section. "steps": [ { "name": "OpenIdServer", "OpenIdServer": { "AccessTokenFormat": 0, "Authority": null, "CertificateStoreLocation": null, "CertificateStoreName": null, "CertificateThumbprint": null, "AuthorizationEndpointPath": "/connect/authorize", "LogoutEndpointPath": "/connect/logout", "TokenEndpointPath": "/connect/token", "UserinfoEndpointPath": "/connect/userinfo", "GrantTypes": [ "authorization_code", "refresh_token" ], "UseRollingTokens": false } }] In the specific content type list only allow the creation of the new content item of the selected type In the admin page, you have a Content Types submenu under the Content menu, where you can list all of the content items. If you click on one of those (for example the Article) there was a green New button where you can create any type of content item that is creatable. Now with a new improvement, the UI responds to the type of the selected content type and (if the Content Type is marked as creatable) you can create only a new content item of the selected type. Here you could see the green button has a text: New Article. New multi-tenant Orchard Core platform GovBuilt has over 30 years of government software experience. They worked with government employees, contractors, and citizens to build a best-in-class online solution that streamlines the permitting and licensing process. They offer a GovBuilt Platform built for Government. And they are using Orchard Core to build their solution! They have several tenants, and https://pottcounty.govbuilt.com/ is one of that! Demos Custom Admin Tree module with taxonomy terms menu You can find a new module in this repository called ThisNetWorks.OrchardCore.AdminTree and a new theme here, called ThisNetWorks.OrchardCore.Themes. If you clone these repositories and add them to your Orchard Core solution you will see a new module under Configuration -> Fetaures called ThisNetWorks Admin Tree Menus. ThisNetWorks Admin Tree module displays content items based on a URL tree or taxonomy structure. This module presents a taxonomy and it's associated terms in a tree menu. The primary purpose of this menu is intended to provide a way to manage complex taxonomies, in combination with a navigation system that makes manages those terms, and content items easier. Let's enable this feature! Now go Design -> Themes and make the ThisNetWorks Admin Theme as the current theme. This adapts the default admin theme to support the menu's on the left sidebar to include clickable entries on tree nodes (i.e. nodes that contain child items can also contain a link to an entry). To be able to test the current capabilities of this solution quickly, you can use a recipe (Configuration -> Recipes) called Categories, that contains sample content items and taxonomy for a taxonomy menu tree. After you run this recipe you should see the following admin menu structure. Here you can see a Categories option with several sub-items. Categories is a taxonomy with the Category term content type and this admin menu shows you the structure of the Categories taxonomy in a clickable way. For example, if you select Motorbike, the site lists you all the content items that have this taxonomy and the category of that is Motorbike. If you click on the blue Create Leaf Article button you can create a content item that has a permalink and the Categories taxonomy will be set to Motorbike by default. Let's see what will happen if you click on the View button near the Articles content item, that is the root term content item of the Categories taxonomy. As you can see, users in the front-end can navigate between the different levels of terms and when navigating between the different content items, you can use different kinds of badges to show the terms and of course, the URL reflects this change as well. This feature is under development and we hope that this will be part of Orchard Core soon! If you are interested in this demo don't forget to check this video on YouTube! On Lombiq Orchard Dojo Newsletter Now we have 108 subscribers of the Lombiq's Orchard Dojo Newsletter! 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!

Useful and interesting services to enhance your features - Dojo Course

UPDATE (2017-11-22): Dojo Course 2 is released with new, updated videos! Dojo Course is almost over, so we move on to the spicy parts of the Orchard API that enable you to do really interesting things! An in-depth recap on what we did so far in our PersonList feature. Content querying: using Orchard's LINQ-like API, the IContentManager service to retreive content pieces (including usage and optimization points). How to integrate your features into the administration menu? Running code periodically using background tasks. Running code at a specified time using scheduled tasks. Creating system-wide event handlers to be able to communicate with other pieces of logic in an even more loosely tied way. And a little addition to migrations: you can implement an Uninstall method in your Migrations class to add some logic which will run when your feature is being removed from a system (hopefully nobody will use it ;) ). Stay tuned for the (really) last part of the Dojo Course before Christmas! Remember: if you have any questions don't hesitate to ask them by creating a new issue in the Orchard issue tracker with the "discussion" label. Make sure to prefix your thread's title with "Dojo Course - "! We keep an eye on these issues. Also follow us on Twitter to get notified about the latest Dojo Course news, including when a new tutorial is posted. Do you have some feedback about the course? Please send it in.