模板化主要是为了允许非开发人员从 Limyee 电商平台更改文本通信的内容和布局 ,而无需访问和更改任何代码。它在功能上与翻译类似,但翻译只能在每次使用时都使用相同的静态文本,但模板设计包含的数据可以根据上下文自定义消息,例如:根据创建内容在通知中插入内容的用户名和标题。IEmailTemplatePlugin 接口允许您定义和(通过管理中的模板编辑器)编辑插件使用的邮件模板。
为什么/何时应该使用模板?
模板化是 Limyee 电商平台中公认的方法,用于在 Limyee 电商平台生成的任何通信中包含的任何动态数据,同时保持在管理 UI 中动态自定义或更改内容的能力,使用将通信翻译到多个位置成为可能。虽然模板可以用于许多不同的目的,但最突出的用例是发送电子邮件。
了解模板上下文
模板被设计为通用的,您设计一次,可以多次重复使用它,因为每次发送模板时,您可以准确地识别那些内容是相同的和那些内容是不同的。换句话说,您创建了整体设计,同时为以后的数据留下了“洞口”。但是,正因为如此,除非模板有一些数据要插入,否则模板不能单独使用。Limyee 电商平台将此数据称为模板的上下文。每当渲染模板时,都需要一个TemplateContext,并且它必须有模板引擎正在寻找的数据来填充“洞口”。模板上下文本质上是一个盲字典,对象由 Guids 键控存储。注册令牌的插件负责通过使用其 ID 来指定它们在上下文中需要的对象,插件渲染模板负责生成上下文,根据令牌所需的 ID 和对象类型填充上下文。
允许插件使用邮件模板
当您希望插件能够利用模板的功能时,您应该实现 IEmailTemplatePlugin。常见的用法是通知和电子邮件模板,或者您创建的任何其他插件,这些插件可能会向您的用户发送消息,并且您可能希望包含当前上下文或该消息所独有的数据。
与插件翻译类似,模板需要一个控制器来访问检索和呈现功能。您可以根据需要使用多种语言设置默认模板。在定义模板时,可以指定一个 ID、名称、描述和一组上下文数据类型 ID。这些上下文数据类型 ID 对应于模板将使用的数据类型。例如,如果要创建有关博客文章的通知,则上下文类型 ID 应指定博客文章数据类型 ID。这还将允许访问将从博客文章对象公开的其他对象及其属性,例如:博客文章的博客,群组或作者。
private ITemplatablePluginController _controller; public void SetController(ITemplatablePluginController controller) { _controller = controller; } private TokenizedTemplate[] _defaultTemplates; public TokenizedTemplate[] DefaultTemplates { get { if (_defaultTemplates == null) { var myTemplate = new TokenizedTemplate("body") { Name = "Template Body", Description = "Sample template", ContextualDataTypeIds = new[] { PublicApi.BlogPosts.ContentTypeId } }; myTemplate.Set("en-us", @""); _defaultTemplates = new[] { myTemplate }; } return _defaultTemplates; } }
有关 ContentTypeId 与 DataTypeId 的注意事项:每个令牌类别都需要一个唯一的 ID 来表示何时将这些令牌包含在模板编辑器的令牌选择列表中。由于其中一些标记用于内容类型(如博客文章),因此在这些情况下重用了 ContentTypeId。对于不属于内容类型的令牌(例如,点赞或提及),将创建一个新 Id 并将其称为 DataTypeId。
为了实际利用模板引擎,您需要创建一个上下文,并使用模板所需的信息填充它。虽然有多种方法可以执行此操作,但对于我们的示例,我们将使用处理事件然后从中生成电子邮件的方法。您可以在处理事件中了解有关事件的更多信息。
// Register to handle the event in the IPlugin Initialize() method. public void Initialize() { Apis.Get<IBlogPosts>().Events.AfterCreate += BlogPost_AfterCreate; }
在处理事件时,我们会获取博客文章,使用该博客文章创建上下文,使用该上下文渲染模板,然后使用这些渲染后的模板发送电子邮件。
void BlogPost_AfterCreate(BlogPostAfterCreateEventArgs e) { BlogPost post = Apis.Get<IBlogPosts>().Get(e.ContentId); var context = new TemplateContext { PostTarget = "Email" }; context.AddItem(PublicApi.BlogPosts.ContentTypeId, post); string renderedSubject = _controller.RenderTokenString("subject", context); string renderedBody = _controller.RenderTokenString("body", context); Apis.Get<ISendEmail>().Send(new SendEmailOptions { Subject = renderedSubject, Body = renderedBody, ToEmail = "recipient@test.com" }); }
请注意,可能有更好的方法可以将您的插件与 Limyee 电商平台的通知架构集成,这只是使用渲染模板的示例,这些模板可以发送电子邮件。有关将插件设置为通知类型的更多信息,请参阅通知。
使用模板编辑器
此时,我们定义的两个模板都是空白的。在管理中配置插件时,强烈建议使用模板编辑器选项卡创建模板,因此此时可以将现有的示例插件编译并放入Limyee电商平台的bin文件夹中。回收应用程序池后,您可以在“管理”中搜索插件以进行编辑。插件配置将有一个“模板”选项卡,您可以看到模板和语言的选择。此处的选项将对应于您在插件中声明的模板名称,以及您的 Limyee 电商平台站点中安装的语言。
从这里,您可以使用整个 Limyee 电商平台中使用的内容编辑器创建模板。对于启用了模板的编辑器,可以在 插入 > 插入令牌下使用其他选项。
这提供了用于选择令牌和根据令牌类型指定一些选项的额外选项。您可以选择将令牌输出限制为特定长度(长度限制为...)。这对于内容正文标记非常有用,可确保一些间距限制,并将用户吸引到您的网站才能查看其余内容。还可以选择将其与硬编码值或另一个标记化模板的输出进行比较,而不是直接将令牌输出呈现给模板。这对于非文本标记(如 Type Ids 和 Counts)、根据内容类型更改模板的某些部分或隐藏模板的某些部分(如果计数为 0)非常有用。这些设置中的每一个都会添加潜在的新子模板:“截短”允许您在文本被截断后添加一些内容(如省略号或“更多”链接),并且“比较”为您提供了两个不同的选项,用于在比较为真或假时显示的内容。请注意,如果需要,这些模板也可以留空。
在选择“数据类型容器”或“枚举”令牌时,还有其他可用的子模板。(有关令牌类型的详细信息,请参阅为模板注册令牌。例如,选择“Blog Post: Blog”将为您提供一个名为“内容”的子模板。这本质上是基本模板的一个新部分,但现在可以访问与博客相关的令牌(而不仅仅是博客文章)。现在可以在此子模板中使用“插入 > 令牌”来插入博客标记。这将创建另一个嵌套选择模式。请记住您在模板中的位置,因为嵌套的模式可能会令人困惑。您始终可以在每个连续的选择模式上单击“确定”以保存更改,或单击“取消”以放弃更改。
当您启用插件并单击“保存”时,当前模板版本将另存为自定义的默认模板。“还原所有模板”按钮将删除任何自定义并恢复默认模板(在本例中为插件中最初定义的空白模板)。
将创建的模板添加回插件
在编辑器中创建模板后,您可以将它们导回插件以使其成为默认值。如果您需要对模板进行临时更改,或者如果您正在分发插件供其他人使用,这可以作为基点。通过将默认模板内容硬编码到插件模板声明中来定义默认模板内容后,“还原模板”按钮会将所有自定义项恢复为原始默认值。
首先,我们需要导出模板。模板导出会被分组为翻译导出。转到 管理 > 网站 > 插件翻译,然后单击“导出资源”。
在下载的文件中,通过搜索插件的名称或类型来查找您的插件。
将要添加到插件的每个模板的整个<template>节点复制回去。
在将模板插入插件代码之前,需要进行一次文本转换。要正确转义字符串,每个双引号 (") 需要替换为两个双引号 ("")。一个简单的“查找和替换”应该能够完成此操作。
然后,可以将模板内容添加到您的插件中。
public TokenizedTemplate[] DefaultTemplates { get { if (_defaultTemplates == null) { var myTemplate = new TokenizedTemplate(EmailTemplateConstants.Body) { Name = "Template Body", Description = "Sample template", ContextualDataTypeIds = new[] { _dataTypeId } }; myTemplate.Set("en-us", @" <template id=""email_body"" name=""Template Body"" description=""Sample template""> <source><p>${token:1cb699c3-61dd-490f-9bef-0284a1fd3445}的生日时间是:${token:338c1bc7-55ad-4ea0-b29b-8da1bf432d83}。</p></source> <fragments /> </template>"); _defaultTemplates = new[] { myTemplate }; } return _defaultTemplates; } }