Registering custom macro methods

In addition to the default macro methods, you can also create your own methods. Users can then run custom functionality by calling the methods inside macro expressions.

Use the following process to add macro methods into the system:

  1. Define the methods inside a container class.
  2. Register your macro method container for a certain object type or macro namespace.
  3. Deploy the custom classes to both your Xperience administration project and the separate live site application. This ensures that the custom macro method can be resolved by both applications. For more information, see Applying customizations in the Xperience environment.

Defining macro methods

  1. Open your project in Visual Studio.

  2. Add a custom assembly (Class Library project) with class discovery enabled to the solution, or re-use an existing assembly.

  3. Create a new class within the custom project.

  4. Edit the class and add a using statement for the CMS.MacroEngine namespace:

    
    
    
     using CMS.MacroEngine;
    
    
     
  5. Make the class inherit from MacroMethodContainer:

    
    
    
     /// <summary>
     /// Sample MacroMethodContainer class.
     /// </summary>
     public class CustomMacroMethods : MacroMethodContainer
     {
    
     }
    
    
     
  6. Define your methods inside the container class. Macro methods must always have the following signature:

    
    
    
     public static object MyMethod(EvaluationContext context, params object[] parameters)
    
    
    
     

    The EvaluationContext parameter allows you to get information about the context in which the macro containing the method was resolved. For example, you can check the identity of the user in the macro signature (for security purposes) or the values of macro parameters, such as the culture or case sensitivity of string comparisons.

    The parameters array stores the method’s parameters. When the system resolves the method, the values of the arguments pass into the array. You need to define individual parameters via attributes (see below).

    Note

    We strongly recommend that you ensure the following in the code of your methods:

    • Caching – if you load data in the method’s code, use the Xperience caching API to optimize the performance.
    • Security – you need to handle permissions and other security checks manually in the method’s code to avoid security vulnerabilities. To build security conditions, get the UserInfo object representing the user who entered the macro from the User property of the method’s EvaluationContext parameter.
  7. Add the MacroMethod attribute above the method declaration. Specify the following parameters for the attribute:

    • Type – the return type of the method.
    • Comment – comment displayed for the method in the macro autocomplete help.
    • Minimum parameters – the minimum number of parameters that must be specified when calling the method (minimum overload).
  8. Add a MacroMethodParam attribute for each of the method’s parameters. For every parameter, you must specify:

    • Index number (sets the index of the parameter in the params array)
    • Name
    • Data type
    • Comment (appears in the macro autocomplete)
Example



using CMS.MacroEngine;
using CMS.Helpers;

public class CustomMacroMethods : MacroMethodContainer
{
    [MacroMethod(typeof(string), "Combines two strings, or appends a culture suffix when called with one parameter.", 1)]
    [MacroMethodParam(0, "param1", typeof(string), "First part of the string.")]
    [MacroMethodParam(1, "param2", typeof(string), "Second part of the string (optional).")]
    public static object ConnectStrings(EvaluationContext context, params object[] parameters)
    {
        // Branches according to the number of the method's parameters
        switch (parameters.Length)
        {
            case 1:
                // Overload with one parameter
                return ValidationHelper.GetString(parameters[0], "") + " - Resolved in culture: " + context.Culture;

            case 2:
                // Overload with two parameters
                return ValidationHelper.GetString(parameters[0], "") + " - " + ValidationHelper.GetString(parameters[1], "");

            default:
                // No other overloads are supported
                throw new NotSupportedException();
        }
    }
}


Registering macro method containers

After you prepare your macro methods in a container class, register the container by extending an object type or macro namespace.

  1. Edit the class containing your macro method container.
  2. Add a RegisterExtension assembly attribute above the class declaration for each type that you wish to extend (requires a reference to the CMS namespace).

Specify the type parameters for the RegisterExtension attribute in the following format:

[assembly: RegisterExtension(typeof(*\<macro method container class\>*), typeof(*\<extended type\>*))]

You can extend the following types:

  • General system types (string, int, …)
  • Xperience API object types (UserInfo, TreeNode, …)
  • Macro namespaces (SystemNamespace, StringNamespace, MathNamespace, …)
  • Custom types
Example



using CMS;

using CMS.MacroEngine;
using CMS.Helpers;

// Makes all methods in the 'CustomMacroMethods' container class available for string objects
[assembly: RegisterExtension(typeof(CustomMacroMethods), typeof(string))]
// Registers methods from the 'CustomMacroMethods' container into the "String" macro namespace
[assembly: RegisterExtension(typeof(CustomMacroMethods), typeof(StringNamespace))]

public class CustomMacroMethods : MacroMethodContainer
{
...


Result - Calling custom methods in macros

Once you have your custom macro methods implemented and registered, you can call them in macro expressions.

Open any macro code editor in the administration interface. The autocomplete help offers the new methods for the extended types or namespaces.

Custom macro method appearing in the autocomplete of a string property

For example:

  • Append the method to a macro object of the data type that you extended (string in the sample code):

    
    
    
      {% CurrentUser.UserName.ConnectStrings() %}
    
      

    The recommended K# syntax is to use infix notation for the first parameter of methods. You can call the method in the following forms:

    • {% “String1”.ConnectStrings(“String2”) %} – recommended and supported by the autocomplete help.
    • {% ConnectStrings(“String1”, “String2”) %}

– OR –

  • Enter the extended macro namespace, and then call the method:

    
    
      {% String.ConnectStrings("First part", "Second part") %}
    
      

Macro method code samples

The Xperience installation includes code examples of custom macro method registration, which you can add directly to your web project.

Access the samples in your Xperience setup file directory (by default C:\Program Files\Kentico\<version>), under the CodeSamples\CustomizationSamples\ sub-directory.

You can find the macro method examples in the following classes:

  • Macros/CustomMacroMethods.cs – class containing the sample macro methods.
  • Modules/SampleMacroModule.cs – initializes the custom method registration.