4 ways to display something from your module nested within a page in Orchard Core - Orchard Nuggets

Zoltán Lehóczky's avatar
Development, Orchard Nuggets, Module, Widget, Liquid, Click to deploy, Update Content Workflow Task - This week in Orchard (17/04/2020)

A common question during Orchard Core development, something that came up again recently, is how to display something within the context of an Orchard page when that piece of data comes from your module? How can you "inject" something into the Orchard layout when you want to display e.g. a list of products retrieved from an external API? There are a couple of ways to do this depending on what exactly you need. All are fairly straightforward so let's see a quick rundown!

Creating a whole page from you module

If you want a whole page served by just your module then it's really simple: Create a module, add a controller as you'd do in standard ASP.NET Core MVC, make an action produce a view and that's it! The view will be wrapped into the Orchard layout so the theme you've selected will be visible around it: The basic styling will be there, the header and menu, any widgets you have put onto layers...

A page of an Orchard Core website, generated by a module, displayed within the context of the website

Our Training Demo module has a simple sample exactly for this, just check it out and you'll see what we're talking about. The above screenshot comes from our Open-Source Orchard Core Extensions solution BTW.

Creating a widget

Widgets (see official docs) are basically little boxes of content or other functionality that you can put anywhere on the site. For example, an infobox about the site, a search box, a recent articles box, a footer can all be widgets. You can use them in two ways:

Add a widget to a content item with Flow Part: Flow Part can be used to build flexible layouts out of various widgets, including nesting them (like putting widgets into a Container Widget). When you set up Orchard with the built-in Agency recipe and theme then you'll get a Page content type that has Flow Part out of the box:

A view of the Orchard Core admin area when editing a Page content item using the Flow Part layout editor

You can get the same content type from our Helpful Extensions Orchard Core module too.

Another option to use widgets is to put them onto a layer, a sort of container of widgets. There you can place the widget into a global zone, an area of the Orchard layout, like the header, footer, or sidebars. The widgets on a layer will be displayed whenever the layer rule of that layer matches (you can think of it as a logic expression producing a boolean value), like on every page except the home page or on every page but only for authenticated visitors. For more info check out the docs.

The Widgets and Layers admin page of Orchard Core, displaying zones and layers

OK, but how can you create a widget? A widget is just a content item whose content type has its stereotype set as "Widget". You can change this value from the admin from under Content / Content Definitions and also from code. So, basically, the task is to create a content part of yours that'll display the data you want to show from its driver, then create a widget content type where that part is attached. Seems like a lot? It isn't, check out the relevant content part development tutorial again from the Training Demo, including creating a widget.

Injecting a shape into the layout

This can be a lot easier than developing a widget but also less flexible to use. You can also write your own code in a template (like a cshtml Razor file) and inject that into the Orchard layout directly. You can see an example of injecting a shape in the Training Demo module too.

Displaying a shape from a Liquid Widget

The Liquid Widget is a widget that can render a piece of Liquid markup. While there is such a widget in the Agency theme and you can throw it together from the admin quickly too the Helpful Libraries module has it built-in as well.

With this widget and Orchard's pretty advanced Liquid support you can of course just write Liquid directly. However, for more complex apps maintaining templates editable from the admin quickly becomes an issue so we'd recommend keeping code in your modules and themes. The good news is that once you have a piece of Razor code in a cshtml template (or Liquid in a .liquid template) then you can just display it from a Liquid Widget! For example, if you have a WeatherData.cshtml template fetching some weather information from an external API then you can display it from a Liquid Widget, and thus use it just as any widget with this little piece of code:

{% shape "WeatherData" %}

There's more to it, check out the docs on the shape Liquid tag.

Conclusion

Pretty much that's it. There are other ways too but these are the most straightforward and most flexible ones. Do you have another technique you'd like others to know? Add below in the comments!

This post is part of our Orchard Nuggets series where we answer common Orchard questions, be it about user-facing features or developer-level issues. Check out the other posts for more such bite-sized Orchard tips and let us know if you'd have another question!

9 Comments

  • bora said Reply

    Hello Zoltan,

    I am new to Orchard Core and sometimes I ask for help on Github. However, there is a point where I am not sure of the implementation and after reading your article on https://orcharddojo.net/blog/4-ways-to-display-something-from-your-module-nested-within-a-page-in-orchard-core-orchard-nuggets I thought I need to ask this question directly to you.



    I want to put a Banner on the Layout which can be changed by the site owner. I created a Banner Content Type in the admin. I put the Image Field. Then, I created a template in the Visual Studio (not in the admin UI). I named the template Banner.liquid, then Content-Banner.liquid. However, none of them works as expected and the Banner does not Show up on the Layout.

    I don’t want to put that as a widget on the Layer and a specific Zone because I want the site owner to display it with all other content items at the same palce in the Admin UI.
    What should I do at this point?

    I tried your suggestion under the subheader “Displaying a shape from a Liquid Widget” yet it didn’t work etiher. Neither {% shape "banner", alias: "alias:main-banner" %} nor {% shape "widget", alias: "alias:main-banner" %} didn’t solve the problem. I believe I am missing some point. I looked at official documents and all sources I could find on the net. Can you please at least point me to the right direction to find out more on this topic?

    Regards,


    Bora

    • Zoltán Lehóczky said Reply

      Hi Bora!

      Note that shapes are case-sensitive. So if you have a Banner.liquid in your theme then only {% shape "Banner" %} will display it. Be sure to turn on the theme of if you put the template into a module, then the module; the overrides not having an effect points to something like this.. You don't need to use the alias attribute if you're displaying a shape directly.

      Otherwise, {% shape "banner", alias: "alias:main-banner" %} should work if your content type has Alias Part attached and the alias is indeed "main-banner".

      • Bora said Reply

        Dear Zoltan,

        "Banner" content type has an alias part and an image field attached to it. Since I wish to use Banner type in different parts of the layout with different instances, I thought alias would be a good differentiator per instance. "Banner.liquid

        • bora said Reply

          "Banner.liquid" file is in the "Views" folder of the Theme. It has a simple, single line code: "<img src="{{ Model.ContentItem.Content.Banner.ImageField.Paths[0] | asset_url }}"
          However, {% shape "banner", alias: "alias:main-banner" %} does not return anything but "src://media/" when put on the Layout.liquid

        • Zoltán Lehóczky said Reply

          OK, so the shape display does work, the problem is somewhere in the img tag. Is your field named "ImageField" (the technical name you've given to it when you added it)? The text in Model.ContentItem.Content.Banner._ImageField_.Paths[0] should be that technical name.

          • Bora said Reply

            Yes, the Media Field's technical name is ImageField in the Banner content type. <img src="{{ Model.ContentItem.Content.Banner._ImageField_.Paths[0] | asset_url }}" didn't work either. Is there any way to see the Model object like a Json output. I saw in the video that Sebastien does it with the template from the Admin, yet is it possible with local file from the Theme? I couldn't a way to do this? I agree with you that the "asset_url" filter seems to be working, yet the Model object looks like empty.

            • Zoltán Lehóczky said Reply

              I meant to _underline_ ImageField, you don't need underscores in the Liquid tag :). Yes, if you export Banner content items with the Deployment feature (enabled by default in some built-in setup recipes) then you'll be able to see the content structure in JSON, and then you can map that to the expression in the tag.

  • Bora said Reply

    Do you mind if I move this issue to Github? Because I think I am still missing something, maybe in my file configuration because as standalone shape "Banner" does not work. However, if I stereotype it as a "Widget" and put into a Zone itself like "Main Banner" it works like a charm. At least, I can provide screenshots and detailed information in Github, if someone requests.

Add a Comment