How to programatically control placement of fields on a part

Topics: Customizing Orchard, Writing modules
Sep 14, 2013 at 7:32 AM
My module needs a particular content type that only needs to make use of the existing Text, Input and Boolean fields. So in the migrations class I call AlterPartDefinition to create a Part and add the fields I need to this. Then I call AlterTypeDefinition to add this part to the content type. I don't need or have defined a MyPartRecord, MyPart, MyPartDriver, etc classes in code in the module.

This all works nicely and I can create create/edit content items of this type via the admin UI.

However, by default the edit view displays all the input fields first, then text fields, then boolean fields. I need to display fields in a particular order (eg. After the "Is Insured?" checkbox, I want the "Insurance History" text box to be displayed).

Is there a way to control the order of the fields when I add them to the part in the migrations class? I know that I can go in and edit the Content Type via the admin UI and adjust the placement by dragging and dropping, however I really want the field order set correctly when the module is installed without the need for manual intervention afterwards.
Sep 14, 2013 at 8:18 AM
I figured it out. This might be useful for others...
  1. In my module I added a reference to the Orchard.ContentTypes project.
  2. Added "using Orchard.ContentTypes.Extensions" to the top of my migrations class
  3. When defining the content type I called .Placement() function to change the placement of fields as required.
        public int UpdateFrom1()
        {
            // Note. The part is named the same as the content item because I want the fields to be
            // treated as though the fields are directly associated with the content type in the admin UI.

            ContentDefinitionManager.AlterPartDefinition("CustomContentType", part => part 
                .Attachable(false)
                .WithField("MyFieldOne", cfg => cfg.OfType("InputField"))
                .WithField("MyFieldTwo", cfg => cfg.OfType("InputField"))
                .WithField("MyFieldThree", cfg => cfg.OfType("BooleanField"))
                .WithField("MyFieldFour", cfg => cfg.OfType("TextField"))
                .WithField("MyFieldFive", cfg => cfg.OfType("BooleanField"))
            );

            // By default all input fields will be displayed first, then all text fields, then all boolean fields. 
            // The call to placement below will ensure fields are displayed in the desired order.

            ContentDefinitionManager.AlterTypeDefinition("CustomContentType", t => t
                .WithPart("CustomContentType")
                .WithPart(typeof(CommonPart).Name)
                .WithPart(typeof(IdentityPart).Name)
                .Creatable(true)
                .Draftable(false)
                .Placement(PlacementType.Editor, "Fields_Common_Text_Edit", "MyFieldFour", "Content", "10")
                .Placement(PlacementType.Editor, "Fields_Boolean_Edit", "MyFieldFive", "Content", "11")
            );

            return 2;
        }