Custom Fields Convention

The custom fields is not a new concept in Blogifier, I've wrote about it long ago and it exists and used in the current code base. It looks somewhat like this:

This is a CustomFields table and AuthorId column is actually convention based - if it is 0 it means this field is for the blog, if it has value greater than 0 then it belongs to the author with specified ID. On the back-end, there methods to get and save blog settings object, where each setting pulled from this table, so that blog theme saved and retrieved for author ID = 0 and field name = blog-theme.

This is very generic and it works in simple scenarios, but what if there need for more structural data? For example, I want to add custom field to the post? Well, could add another column like PostId, but then what if a theme needs a field saved for customization? It can go on and on, resulting in the large, complex and, most importantly, constantly changing table.

The other way is to add a conventions, just like 0 author ID means owned by a blog, same can apply to the field name to be in specific format. For example, for a very common list of social buttons, I want a UI to collect user input. User should be able to enter social account name, like facebook or twitter, and link to go when visitor clicks the button. There is also a rank, to sort buttons as you like it. data/rtur/2020/5/social-field-ui.jpg

To make this possible, I would need to follow a convention like social|<name>|<rank>: social|facebook|1. And back-end could expose social accounts via helper method. The helper method in the custom fields repository would return convention-based List<SocialField>, where each item would be extended custom field, with extended properties pulled by parsing the Name.

public class CustomField
{
  public int Id { get; set; }
  public int AuthorId { get; set; }
  public string Name { get; set; }
  public string Content { get; set; }
}

public class SocialField : CustomField
{
  public string Title { get; set; }
  public string Icon { get; set; }
  public int Rank { get; set; }
}

And the parser itself to map custom field to extended social field.

foreach	(CustomField field in customFields){
  var fieldArray = field.Name.Split('|');
  if(fieldArray.Length > 2){
    socials.Add(new SocialField{
      Title = fieldArray[1].Capitalize(),
      Icon = $"fa-{fieldArray[1]}",
      Rank = int.Parse(fieldArray[2]),
      Id = field.Id,
      Name = field.Name,
      AuthorId = field.AuthorId,
      Content = field.Content
    });
  }
}

This is what social field looks like in the debug watch window:

On the front-end, theme can add social buttons very easily now.

@inject IDataService DataService
@{
  var social = await DataService.CustomFields.GetSocial();
}
<div class="social-area">
  @foreach (var field in social)
  {
    <a href="@field.Content"><i class="fa @field.Icon"></i></a>
  }
</div>

If later there a need to add a custom fields to the post, it can be done too, with something like post|<id>|<title>. Then, similarly, add override with post ID and title properties and, optionally, helper to parse and return new field to make it easier to use in UI. Basic rules stay the same: define a convention and follow it whenever you need custom functionality for your blog. Some common things like social buttons and few others can be added as features to the core application, but others can be done at individual blog or at the theme level, with no need for core application to change.

About RTUR.NET

This site is all about developing web applications with focus on designing and building open source blogging solutions. Technologies include ASP.NET Core, C#, Angular, JavaScript and more.