2

I'm creating a custom field type for our responsive image implementation in Sitecore 10.1 and I need a way to display the image using Html.Sitecore().Field("field_name"). I think I'm mostly there but I'm stuck on getting the renderField pipeline to recognize when it's dealing with my custom field type.

The work I've done borrows heavily from the native ImageRenderer class and GetImageFieldValues processor on the pipeline, and the way they handle that is to check args.FieldTypeKey for a value of "image." Unfortunately, that property is an empty string for my custom field and I can't figure out how to get a value in there.

Does anyone know how to populate the RenderPipelineArgs.FieldTypeKey value for a custom field type? Or, alternatively, can anyone suggest a different method for my renderField processor to identify when the field is my custom type?

I can add a field of my custom type to a data template and the control for it renders correctly in Content Editor (i.e., it uses a modified droptree and that functions as expected to select a value). But when I attempt to view the page (Editing mode, Preview mode, or live site) the field isn't included in the rendering.

What I've done so far

  1. Created a custom field type in the core database under sitecore/system/Field Types/Custom Fields
  2. Created a class in my project (ResponsiveImage.cs) to implement the field, and set the Assembly and Class properties of the custom field type to point to it
  3. Created a custom RenderFieldPipeline processor (GetResponsiveImageFieldValue.cs) to render the field and a config file (ResponsiveImage.config) to add it to the renderField pipeline
  4. Added an entry in the <fieldTypes> config node for my custom field type
  5. Published everything

Code

GetResponsiveImageFieldValue.cs

public class GetResponsiveImageFieldValue
{
    public virtual void Process(RenderFieldArgs args)
    {
        Assert.ArgumentNotNull(args, nameof(args));
        if (!IsResponsiveImage(args)) return;

        ResponsiveImageRenderer renderer = this.CreateRenderer();
        ConfigureRenderer(args, renderer);
        SetRenderFieldResults(renderer.Render(), args);
    }

    protected virtual bool IsResponsiveImage(RenderFieldArgs args) => args.FieldTypeKey == "responsive image";

    protected virtual ResponsiveImageRenderer CreateRenderer() => new ResponsiveImageRenderer();

    protected virtual void ConfigureRenderer(RenderFieldArgs args, ResponsiveImageRenderer renderer)
    {
        renderer.Item = args.Item;
    }

    protected virtual void SetRenderFieldResults(RenderFieldResult result, RenderFieldArgs args)
    {
        args.Result.FirstPart = result.FirstPart;
        args.Result.LastPart = result.LastPart;
        args.WebEditParameters.AddRange(args.Parameters);
        args.DisableWebEditContentEditing = true;
        args.DisableWebEditFieldWrapping = true;
        args.WebEditClick =
            "return Sitecore.WebEdit.editControl($JavascriptParameters, \"webedit:chooseresponsiveimage\")";
    }
}

ResponsiveImages.config

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore>
    <commands>
      <command name="webedit:chooseresponsiveimage" type="Sitecore.MyCompany.Foundation.MVC.CustomSitecore.ChooseResponsiveImage, Sitecore.MyCompany.Foundation.MVC" />
    </commands>
    <overrideXmlControls>
      <override xmlControl="Sitecore.Shell.Applications.Media.ResponsiveMediaBrowser" with="/sitecore/client/applications/Dialogs/SelectResponsiveMediaDialog" />
    </overrideXmlControls>
    <pipelines>
      <renderField>
        <processor type="Sitecore.MyCompany.Foundation.MVC.Pipelines.GetResponsiveImageFieldValue, Sitecore.MyCompany.Foundation.MVC" 
                   patch:before="processor[@type='Sitecore.MyCompany.Foundation.MVC.Pipelines.CustomGetImageFieldValue, Sitecore.MyCompany.Foundation.MVC']" />
      </renderField>
    </pipelines>
    <fieldTypes>
      <fieldType name="Responsive Image" type="Sitecore.MyCompany.Foundation.MVC.CustomFields.ResponsiveImage, Sitecore.MyCompany.Foundation.MVC" />
    </fieldTypes>
  </sitecore>
</configuration>

(Note: opted to not include a listing of ResponsiveImage.cs because it just extends our modified droptree class and overwrites the Source property, and it should be irrelevant to the problem at hand.)

Similar SO questions

The only existing question I could find that comes close to this is: How to change the source from an image field programmatically?

The answers to that come very close to where my problem is but don't quite address the FieldTypeKey field itself.

1 Answer 1

4

Quick answer


You can populate it in the field "Type" of your template's field item.

Still confusing?

Here is an image to help you

enter image description here

The image above shows how the type is set in the default image field, pay attention the RawValues is checked, it's just a text value, go to your field item and add the value you want.

If you uncheck raw values to see if your custom field is being shown as an option in the Droplist you should make sure you have a FieldType item created under "/sitecore/system/Field types" in core database.

Detailed answer


Firstly, do you really need a custom field type?

If what you need is to change the rendered HTML for image fields, all you need is a pipeline processor.

Some advice:

  1. Pay attention to the processor's invoking order
  2. Disable all other processors for a while

So, to me your best option is extending the GetImageFieldValue processor and make it recognize your custom field type.

So let's make a few changes.

The processor

    public class GetResponsiveImageFieldValue : GetImageFieldValue
    {
        public virtual void Process(RenderFieldArgs args)
        {
            Assert.ArgumentNotNull(args, nameof(args));
            if (!this.ShouldExecute(args)) return;

            base.Process(args);
        }

        public bool ShouldExecute(RenderFieldArgs args)
        {
            if(!this.IsImage(args))
                return false;
            if (!Sitecore.Context.PageMode.IsNormal)
                return false;
            if (Sitecore.Context.Site == null)
                return false;
            if (Sitecore.Context.Item == null)
                return false;
            if (args.Result != null && string.IsNullOrEmpty(args.Result.FirstPart))
                return false;


            return true;
        }


        protected override bool IsImage(RenderFieldArgs args) => args.FieldTypeKey == "image" || args.FieldTypeKey == "responsive image";
    }

The config patch

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
      <sitecore>
          <pipelines>
              <renderField>
                  <processor patch:instead="processor[@type='Sitecore.Pipelines.RenderField.GetImageFieldValue, Sitecore.Kernel']" type="Sitecore.MyCompany.Foundation.MVC.Pipelines.GetResponsiveImageFieldValue, Sitecore.MyCompany.Foundation.MVC"/>
              </renderField>
          </pipelines>
      </sitecore>
    </configuration>

And the last but not least, if at some point you need to bring images from Content Hub you'll probably have to change your approach.

My main question for you is, do you really need a custom field? If the answer for that is no, a new processor for RenderField pipeline is enough.

This article is about an issue related to RenderField pipeline and a ContentHub instance, it might give you some insights.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.