Adding Settings to a Plugin in NopCommerce (pre-4.00)

Once you’re created a plugin for NopCommerce, you’ll likely want to add the ability to configure settings inside the plugin for reference later.

When adding this capability, we’re going to work on trying to make this as immutable as possible, to follow functional programming as best we can, just because it makes things a little cleaner and puts all of the conversion between the configuration model and settings object.

Locale Keys

First, we’ll set up a class called MyPluginLocaleKeys.cs that holds the different locale keys used to represent the settings descriptions in the Configure page:

public static class MyPluginLocaleKeys
{
    public const string MySetting1 = "Plugins.Misc.MyPlugin.Fields.Settings1";
    public const string MySetting2 = "Plugins.Misc.MyPlugin.Fields.Settings2";
}

Configuration Model

Next, we’ll create a configuration model named Models/MyPluginConfigModel.cs that represents the configure page for the plugin. This will get populated by the plugin’s settings, and then be responsible for receiving user data and saving the setting values provided.

In addition to usually having a 1:1 relationship to the plugin settings, you can also provide DataAnnotations that handle model validity and display names. When providing a NopResourceDisplayName, we’ll use the locale key provided above.

public class MyPluginConfigModel
{
    [Required]
    [NopResourceDisplayName(MyPluginLocaleKeys.Setting1)]
    public string Setting1 { get; set; }

    [NopResourceDisplayName(MyPluginLocaleKeys.Setting2)]
    public string Setting2 { get; set; }
}

Settings Object

Next, create an ISettings implementation in the root of the plugin named MyPluginSettings.cs.

This is going to work a little differently – we’re going to create this to be immutable, so we’ll both initialize it from a config model, create a “default” settings object, and allow for easily converting to a config model.

public class MyPluginSettings : ISettings
{
    // Settings properties
    public string Setting1 { get; private set; }
    public string Setting2 { get; private set; }

    // Initializes from a config model (used for saving values)
    public static MyPluginSettings FromModel(MyPluginConfigModel)
    {
        return new MyPluginSettings()
        {
            Setting1 = model.Setting1,
            Setting2 = model.Setting2
        };
    }

    // Create a "default" settings object that is used when installing plugin
    public static MyPluginSettings Default()
    {
        return new MyPluginSettings()
        {
            Setting1 = "Default setting",
            Setting2 = "Another default setting"
        };
    }

    // Creates a config model to use for the configuration page
    public MyPluginConfigModel ToModel()
    {
        return new MyPluginConfigModel()
        {
            Setting1 = Setting1,
            Setting2 = Setting2
        }
    }
}

We use private set here to make sure we initialize the settings object from a configuration model (when saving) and disallow the ability to change the settings object – making it immutable.

Base Plugin Class

Next, create the base plugin class (named MyPluginPlugin.cs, so for example, EnhancedLoggingPlugin.cs, used for defining the type of plugin and defining the install/uninstall options. We’ll do a few special things

public class MyPluginPlugin : BasePlugin, YOUR_PLUGIN_INTERFACE
{
    private readonly ISettingService _settingService;

    public MyPluginPlugin(
        ISettingService settingService)
    {
        _settingService = settingService;
    }

    public override void Install()
    {
        // saves the desired default values for settings
        _settingService.SaveSetting(MyPluginSettings.Default());
        
        // Adds all locale resources
        foreach (var field in typeof(MyPluginLocaleKeys).GetFields())
	{
	    string key = (string)field.GetValue(null);
	    // Converts the key above to a value (capital letters separated by space)
	    string value = Regex.Replace(field.Name, "([a-z])([A-Z])", "$1 $2");
	    value = Regex.Replace(value, "([A-Z])([A-Z][a-z])", "$1 $2");

	    this.AddOrUpdatePluginLocaleResource(key, value);
	}

        base.Install();
    }

    public override void Uninstall()
    {
        // Delete the plugin settings from DB
        _settingService.DeleteSetting<MyPluginSettings>();

        // Delete all plugin locales using reflection
        foreach (var field in typeof(MyPluginLocaleKeys).GetFields())
	{
	    this.DeletePluginLocaleResource((string)field.GetValue(null));
	}

        base.Uninstall();
    }
}

Configure Controller and View

The final step is creating both the Configuration controller and view to finish the ability to view and save plugin settings data. Create the Controllers/MyPluginConfigController.cs file:

[AdminAuthorize]
public class SliExportController : BasePluginController
{
    private readonly MyPluginSettings _settings;
    private readonly ISettingService _settingService;
    private readonly ILocalizationService _localizationService;

    public SliExportController(
        SliExportSettings sliExportSettings,
	ISettingService settingService,
	ILocalizationService localizationService)
    {
	_sliExportSettings = sliExportSettings;
	_settingService = settingService;
	_localizationService = localizationService;
    }

    [ChildActionOnly]
    public ActionResult Configure()
    {
        return View("~/Plugins/PLUGIN_EXPORT/Views/Configure.cshtml", _settings.ToModel());
    }

    [HttpPost]
    [ChildActionOnly]
    public ActionResult Configure(MyPluginConfigModel model)
    {
        if (!ModelState.IsValid)
	{
	    return Configure();
	}

	_settingService.SaveSetting(SliExportSettings.FromModel(model));
        SuccessNotification(
            _localizationService.GetResource("Admin.Plugins.Saved"));

        return Configure();
    }

Then create the Views/Configure.cshtml file:

@{
    Layout = "";
}
@model YOUR_CONFIG_MODEL
@using Nop.Web.Framework;
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div class="panel-group">
        <div class="panel panel-default">
            <div class="panel-body">
                <div class="form-group">
                    <div class="col-md-3">
                        @Html.NopLabelFor(model => model.Setting1)
                    </div>
                    <div class="col-md-9">
                        @Html.NopEditorFor(model => model.Setting1)
                        @Html.ValidationMessageFor(model => model.Setting1)
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-3">
                        @Html.NopLabelFor(model => model.Setting2)
                    </div>
                    <div class="col-md-9">
                        @Html.NopEditorFor(model => model.Setting2)
                        @Html.ValidationMessageFor(model => model.Setting2)
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-3">
                        &nbsp;
                    </div>
                    <div class="col-md-9">
                        <input type="submit" name="save" class="btn bg-blue" value="@T("Admin.Common.Save")" />
                    </div>
                </div>
            </div>
        </div>
    </div>
}

Leave a Reply

Your email address will not be published. Required fields are marked *