Adding custom fields to newsletters subscribers
Hi,
We are using SF 4.1 SP2 in our website, we want to know is it possible to add custom fields to the newsletters subscribers? currently the available fields are "first name", "last name" and "email", we need to add more other fields such as "address", "company name", "phone" and "title".
I found a thread mentioned that it will be available in SF 4 and have all the options of the "Generic contents", is it available yet?
Thanks.
Hello Amrelsayed,
It will be possible with Q2 release which is scheduled for release due in the first half of August.
Best wishes,
Ivan Dimitrov
the Telerik team
Hi Ivan,
We upgraded our website to 4.2 released 10 August, however I can't find how to add custom fields to the email campaigns, can't we accomplish this as in the News/Blogs built-in modules?
Thanks.
Hello Amrelsayed,
You need to do it programmatically
sample
metaManager.CreateMetaType(
typeof
(Subscriber));
var myField=metaManager.CreateMetafield(
"MyOrganization"
);
metaManager.GetMetaType(
typeof
(Subscriber)).Fields.Add(myField);
metaManager.SaveChanges();
Thanks Ivan,
I have created a sample code to create a custom field,
var metaMan = MetadataManager.GetManager();
var dynType = metaMan.GetMetaType(
typeof
(Subscriber));
if
(dynType !=
null
)
metaMan.Delete(dynType);
metaMan.SaveChanges(
true
);
metaMan = MetadataManager.GetManager();
dynType = metaMan.CreateMetaType(
typeof
(Subscriber));
var metaField = metaMan.CreateMetafield(
"Title"
);
metaField.DBSqlType =
"NVARCHAR(100)"
;
metaField.DBType =
"LONGVARCHAR"
;
metaField.ClrType =
typeof
(
string
).Name;
dynType.Fields.Add(metaField);
metaMan.SaveChanges(
true
);
Any updates Ivan?
Hi Amrelsayed,
What is the full type (including namespace) of the Subscriber class? Do you have the model of this class compiled into an assembly and added to the bin folder of your site?
Regards,
Radoslav Georgiev
the Telerik team
Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's DevProConnections Awards. We are competing in mind-blowing 20 categories and every vote counts! VOTE for Telerik NOW >>
Hi Radoslav,
it is "Telerik.Sitefinity.Newsletters.Model.Subscriber" and the "Telerik.Sitefinity.Model.dll" is included in the bin folder.
Hello Amrelsayed,
Please try the bellow:
var metaMan = MetadataManager.GetManager();
var dynType = metaMan.GetMetaType(
typeof
(Subscriber));
var metaField = metaMan.CreateMetafield(
"Title"
);
metaField.DBType =
"LONGVARCHAR"
;
metaField.ClrType =
typeof
(
string
).FullName;
dynType.Fields.Add(metaField);
metaMan.SaveChanges(
true
);
Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's DevProConnections Awards. We are competing in mind-blowing 20 categories and every vote counts! VOTE for Telerik NOW >>
Hello Radoslav,
I created custom fields using the snippet code below :
var metaMan = MetadataManager.GetManager();
var dynType = metaMan.GetMetaType(
typeof
(Subscriber));
if
(dynType ==
null
)
dynType = metaMan.CreateMetaType(
typeof
(Subscriber));
var metaField = metaMan.CreateMetafield(
"Title"
);
metaField.DBSqlType =
"NVARCHAR(100)"
;
metaField.DBType =
"LONGVARCHAR"
;
metaField.ClrType =
typeof
(
string
).FullName;
dynType.Fields.Add(metaField);
var metaField = metaMan.CreateMetafield(
"CompanyName"
);
metaField.DBSqlType =
"NVARCHAR(100)"
;
metaField.DBType =
"LONGVARCHAR"
;
metaField.ClrType =
typeof
(
string
).FullName;
dynType.Fields.Add(metaField);
metaMan.SaveChanges(
true
);
However, I can see these metafields added in the database table (please refer to DatabaseTables.png) but they are not shown up in the place holders used in the campaigns templates creation on the administration (please refer to NewslettersBackend.png)
Is there any workaround to add these meta fields to the template placeholders list so it can be used in the messages sent by the campaigns?
Thanks.
Would someone please let us know when to expect feedback over that matter? We have been trying to get this to work for close to 4 weeks and we have a project that is pending release on this request so we would appreciete some support here.
Hi Amrelsayed,
Thank you for getting back to us, and please excuse us for the inconvenience. Indeed the dynamic mergeTags that are added programatically are not displayed in the dropdown, since this is a template i.e. you don't know which mailing list you'll be using, so only the default fields are included. This is a valid feature request, thank you for pointing out the need for it, I'll make sure we get it addressed. What you can do, in the meantime, as a quick workaround, would be to use the programatic name of the field and address it in the template using the same syntax as with the other fields - I have just tried it on a local project and it gets resolved properly. For instance, if you have a field "CompanyName
" you can display it in the email that's sent by writing in the template |Subscriber.CompanyName
| and it will be resolved dynamically for each subscriber. Example:
My template is:
Hello, member of |Subscriber.Organization| ,
Welcome!
the database table:
And the email received:
Hello, member of Telerik ,
Welcome!
If you need any further assistance implementing this functionality, or have some additional questions, pleae do not hesitate to let us know.
Best wishes,
Boyan Barnev
the Telerik team
Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's DevProConnections Awards. We are competing in mind-blowing 20 categories and every vote counts! VOTE for Telerik NOW >>
Hello Amrelsayed,
Yes, it's possible to map a n external template for the Template form - please use HostType:
Telerik.Sitefinity.Modules.Newsletters.Web.UI.Forms.TemplateForm
You can find below the defualt template we've implemented for that form.
<%@ Control Language="C#" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sitefinity" %>
<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI.Fields" TagPrefix="sitefinity" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Modules.Newsletters.Web.UI.Wizards.Steps" TagPrefix="sitefinity" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Modules.Pages.Web.UI.Fields" TagPrefix="sitefinity" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Modules.Newsletters.Web.UI" TagPrefix="newsletters" %>
<
sitefinity:ResourceLinks
id
=
"resourcesLinks"
runat
=
"server"
>
<
sitefinity:ResourceFile
JavaScriptLibrary
=
"JQuery"
/>
<
sitefinity:ResourceFile
Name
=
"Styles/Window.css"
/>
</
sitefinity:ResourceLinks
>
<
sitefinity:FormManager
id
=
"formManager"
runat
=
"server"
/>
<
fieldset
class
=
"sfNewItemForm"
>
<
asp:LinkButton
ID
=
"backButton"
runat
=
"server"
CssClass
=
"sfBack"
>
<
asp:Label
runat
=
"server"
ID
=
"backLabel"
Text='<%$Resources:NewslettersResources, BackToMessageTemplates %>' />
</
asp:LinkButton
>
<
sitefinity:SitefinityLabel
id
=
"formTitleControl"
runat
=
"server"
WrapperTagName
=
"h1"
HideIfNoText
=
"false"
/>
<
sitefinity:Message
ID
=
"messageControl"
runat
=
"server"
ElementTag
=
"div"
CssClass
=
"sfMessage sfDialogMessage"
RemoveAfter
=
"30000"
FadeDuration
=
"10"
/>
<
div
id
=
"mainForm"
runat
=
"server"
>
<
div
class
=
"sfForm sfFirstForm"
>
<
div
class
=
"sfFormIn"
>
<
sitefinity:TextField
ID
=
"templateName"
runat
=
"server"
DisplayMode
=
"Write"
Title='<%$Resources:NewslettersResources, TemplateName %>'
CssClass="sfTitleField">
<
ValidatorDefinition
Required
=
"true"
MessageCssClass
=
"sfError"
/>
</
sitefinity:TextField
>
</
div
>
</
div
>
<
div
class
=
"sfForm"
>
<
div
class
=
"sfFormIn"
>
<
div
class
=
"sfNewsletterCampaignType"
>
<
sitefinity:SitefinityLabel
id
=
"selectTemplateType"
Text='<%$Resources:NewslettersResources, SelectTemplateType %>' runat="server" WrapperTagName="h2" CssClass="sfTxtLbl" HideIfNoText="false" />
<
ol
class
=
"sfRadioList"
>
<
li
class
=
"sfNewsletterRichText"
>
<
asp:RadioButton
ID
=
"htmlTemplateRadio"
runat
=
"server"
Text='<%$Resources:NewslettersResources, RichTextHtml %>'
Checked="true"
GroupName="templateType" />
<
p
class
=
"sfDescription"
>
<
asp:Literal
ID
=
"htmlTemplateDescription"
runat
=
"server"
Text='<%$Resources:NewslettersResources, RichTextHtmlDescription %>' />
</
p
>
</
li
>
<
li
class
=
"sfNewsletterPlainText"
>
<
asp:RadioButton
ID
=
"plainTextTemplateRadio"
runat
=
"server"
Text='<%$Resources:NewslettersResources, PlainText %>'
GroupName="templateType" />
<
p
class
=
"sfDescription"
>
<
asp:Literal
ID
=
"plainTextTemplateDescription"
runat
=
"server"
Text='<%$Resources:NewslettersResources, PlainTextDescription %>' />
</
p
>
</
li
>
<
li
class
=
"sfNewsletterLikeWebPage"
>
<
asp:RadioButton
ID
=
"standardTemplateRadio"
runat
=
"server"
Text='<%$Resources:NewslettersResources, LikeAWebPage %>'
GroupName="templateType" />
<
p
class
=
"sfDescription"
>
<
asp:Literal
ID
=
"standardTemplateDescription"
runat
=
"server"
Text='<%$Resources:NewslettersResources, LikeAWebPageDescription %>' />
</
p
>
</
li
>
</
ol
>
</
div
>
</
div
>
</
div
>
<
div
class
=
"sfForm"
>
<!-- HTML MESSAGE -->
<
ol
id
=
"htmlTextPanel"
runat
=
"server"
class
=
"sfFormIn"
>
<
li
><
newsletters:MergeTagSelector
id
=
"htmlMergeTagSelector"
runat
=
"server"
/></
li
>
<
sitefinity:HtmlField
id
=
"htmlTextControl"
runat
=
"server"
DisplayMode
=
"Write"
WrapperTag
=
"li"
CssClass
=
"sfContentField sfFormSeparator"
Title="<%$Resources:NewslettersResources, CampaignType %>" />
</
ol
>
<!-- END HTML MESSAGE -->
<!-- PLAIN TEXT TEMPLATE -->
<
ol
id
=
"plainTextPanel"
runat
=
"server"
class
=
"sfFormIn"
style
=
"display:none;"
>
<
li
>
<
asp:Label
ID
=
"titleLabel"
runat
=
"server"
Text='<%$Resources:NewslettersResources, CampaignType %>' CssClass="sfTxtLbl" />
<
newsletters:MergeTagSelector
id
=
"mergeTagSelector"
runat
=
"server"
/>
</
li
>
<
li
>
<
asp:TextBox
id
=
"plainTextControl"
runat
=
"server"
TextMode
=
"MultiLine"
Rows
=
"9"
CssClass
=
"sfTxt"
></
asp:TextBox
>
</
li
>
</
ol
>
<!-- END PLAIN TEXT TEMPLATE -->
<!-- INTERNAL PAGE MESSAGE -->
<
div
id
=
"internalPagePanel"
runat
=
"server"
class
=
"sfFormIn"
style
=
"display:none;"
>
<
sitefinity:PageTemplateField
id
=
"baseTemplateField"
runat
=
"server"
DisplayMode
=
"Write"
Title='<%$Resources:NewslettersResources, BaseTemplateTitle %>' />
<
div
class
=
"sfOnlyChildInDependentGroup"
>
<
asp:LinkButton
ID
=
"composeTemplateInPageEditorButton"
runat
=
"server"
OnClientClick
=
"return false;"
CssClass
=
"sfLinkBtn"
>
<
asp:Label
ID
=
"leditInternalPageLink"
runat
=
"server"
Text='<%$Resources:NewslettersResources, ComposeTheTemplateInPageEditor %>' CssClass="sfLinkBtnIn" />
</
asp:LinkButton
>
</
div
>
</
div
>
<!-- END INTERNAL PAGE MESSAGE -->
</
div
>
</
div
>
<
div
class
=
"sfButtonArea sfMainFormBtns"
>
<
asp:LinkButton
ID
=
"saveChangesButton"
runat
=
"server"
CssClass
=
"sfLinkBtn sfSave"
OnClientClick
=
"return false;"
>
<
asp:Label
ID
=
"saveChangesLabel"
runat
=
"server"
Text='<%$Resources:NewslettersResources, CreateThisTemplate %>' CssClass="sfLinkBtnIn" />
</
asp:LinkButton
>
<
span
>
<
asp:Literal
ID
=
"orLiteral"
runat
=
"server"
Text='<%$Resources:Labels, or %>'></
asp:Literal
>
</
span
>
<
a
href
=
"javascript:close();"
class
=
"sfCancel"
>
<
asp:Literal
ID
=
"cancelLiteral"
runat
=
"server"
Text='<%$Resources:Labels, Cancel %>'></
asp:Literal
>
</
a
>
</
div
>
<
asp:HiddenField
ID
=
"webServiceUrlHidden"
runat
=
"server"
/>
<
asp:HiddenField
ID
=
"formIdHidden"
runat
=
"server"
/>
</
fieldset
>
<
script
type
=
"text/javascript"
>
$("body").addClass("sfFormDialog");
function setForm(editedTemplate)
var formId = $get('<%= formIdHidden.ClientID %>').value;
$find(formId).loadTemplate(editedTemplate);
</
script
>
Hi Boyan,
Thanks a lot it works well for the "Message Templates" page (please review MessageTemplate.png), but if I create a campaign template from scratch (please review CreateCampaign.png) and select (Rich Text or Plain Text), the template form doesn't share the same user control we mapped (please review CampaignTemplate.png).
Please advice whether this is using a different template and how to extend it.
Thanks.
Hi Amrelsayed,
Yes, as you have correctly pointed out, it's a different control and template. Please find below the default template used:
<%@ Control Language="C#" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sitefinity" %>
<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI.Fields" TagPrefix="sitefinity" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Modules.Newsletters.Web.UI" TagPrefix="newsletters" %>
<
sitefinity:ResourceLinks
id
=
"resourcesLinks"
runat
=
"server"
>
<
sitefinity:ResourceFile
JavaScriptLibrary
=
"JQuery"
/>
</
sitefinity:ResourceLinks
>
<
sitefinity:FormManager
id
=
"formManager"
runat
=
"server"
/>
<
sitefinity:Message
ID
=
"messageControl"
runat
=
"server"
ElementTag
=
"div"
CssClass
=
"sfMessage sfDialogMessage"
RemoveAfter
=
"30000"
FadeDuration
=
"10"
/>
<
div
id
=
"mainForm"
runat
=
"server"
>
<!-- HTML MESSAGE -->
<
div
id
=
"htmlTextPanel"
runat
=
"server"
class
=
"sfForm sfFirstForm"
style
=
"display:none;"
>
<
ol
class
=
"sfFormIn"
>
<
li
>
<
newsletters:MergeTagSelector
id
=
"htmlMergeTagSelector"
runat
=
"server"
/>
</
li
>
<
sitefinity:HtmlField
id
=
"htmlTextControl"
runat
=
"server"
DisplayMode
=
"Write"
CssClass
=
"sfContentField sfFormSeparator"
Title='<%$Resources:NewslettersResources, CampaignMessage %>' WrapperTag="li" />
<
li
class
=
"sfFormSeparator"
>
<
h2
><
asp:Literal
ID
=
"plainTextVersionLabel_Html"
runat
=
"server"
Text='<%$Resources:NewslettersResources, PlainTextVersion %>' /></
h2
>
<
sitefinity:ChoiceField
id
=
"plainTextGenerationHtml"
runat
=
"server"
DisplayMode
=
"Write"
RenderChoicesAs
=
"RadioButtons"
Title='<%$Resources:NewslettersResources, PlainTextVersionDescription %>'>
<
Choices
>
<
sitefinity:ChoiceItem
Text='<%$Resources:NewslettersResources, AutomaticallyGeneratePlainTextVersion %>' />
<
sitefinity:ChoiceItem
Text='<%$Resources:NewslettersResources, ManuallyEnterPlainTextVersion %>' />
</
Choices
>
</
sitefinity:ChoiceField
>
<
div
style
=
"display:none;"
>
<
asp:TextBox
id
=
"plainTextVersionHtml"
runat
=
"server"
TextMode
=
"MultiLine"
Rows
=
"9"
CssClass
=
"sfTxt"
></
asp:TextBox
>
</
div
>
</
li
>
</
ol
>
</
div
>
<!-- END HTML MESSAGE -->
<!-- PLAIN TEXT MESSAGE -->
<
div
id
=
"plainTextPanel"
runat
=
"server"
class
=
"sfForm sfFirstForm"
style
=
"display:none;"
>
<
ol
class
=
"sfFormIn"
>
<
li
>
<
asp:Label
ID
=
"titleLabel"
runat
=
"server"
Text='<%$Resources:NewslettersResources, CampaignMessage %>' CssClass="sfTxtLbl" />
<
newsletters:MergeTagSelector
id
=
"mergeTagSelector"
runat
=
"server"
/>
</
li
>
<
li
>
<
asp:TextBox
id
=
"plainTextControl"
runat
=
"server"
TextMode
=
"MultiLine"
Rows
=
"9"
CssClass
=
"sfTxt"
></
asp:TextBox
>
</
li
>
</
ol
>
</
div
>
<!-- END PLAIN TEXT MESSAGE -->
<!-- INTERNAL PAGE MESSAGE -->
<
div
id
=
"internalPagePanel"
runat
=
"server"
class
=
"sfForm sfFirstForm"
style
=
"display:none;"
>
<
ol
class
=
"sfFormIn"
>
<
li
>
<
asp:Label
ID
=
"Label3"
runat
=
"server"
Text='<%$Resources:NewslettersResources, CampaignMessageComposedAsAWebPage %>' CssClass="sfTxtLbl" />
<
asp:LinkButton
ID
=
"editInternalPageLink"
runat
=
"server"
OnClientClick
=
"return false;"
CssClass
=
"sfLinkBtn sfChange"
>
<
asp:Label
ID
=
"leditInternalPageLink"
runat
=
"server"
Text='<%$Resources:NewslettersResources, EditCampaignMessage %>' CssClass="sfLinkBtnIn" />
</
asp:LinkButton
>
</
li
>
<
li
class
=
"sfFormSeparator"
>
<
h2
><
asp:Literal
ID
=
"plainTextVersionLabel_Page"
runat
=
"server"
Text='<%$Resources:NewslettersResources, PlainTextVersion %>' /></
h2
>
<
sitefinity:ChoiceField
id
=
"plainTextGenerationPage"
runat
=
"server"
DisplayMode
=
"Write"
RenderChoicesAs
=
"RadioButtons"
Title='<%$Resources:NewslettersResources, PlainTextVersionDescription %>'>
<
Choices
>
<
sitefinity:ChoiceItem
Text='<%$Resources:NewslettersResources, AutomaticallyGeneratePlainTextVersion %>' />
<
sitefinity:ChoiceItem
Text='<%$Resources:NewslettersResources, ManuallyEnterPlainTextVersion %>' />
</
Choices
>
</
sitefinity:ChoiceField
>
<
div
style
=
"display:none;"
>
<
asp:TextBox
id
=
"plainTextVersionPage"
runat
=
"server"
TextMode
=
"MultiLine"
Rows
=
"9"
CssClass
=
"sfTxt"
></
asp:TextBox
>
</
div
>
</
li
>
</
ol
>
</
div
>
<!-- INTERNAL PAGE MESSAGE -->
<!-- EXTERNAL PAGE MESSAGE -->
<
div
id
=
"externalPagePanel"
runat
=
"server"
class
=
"sfForm sfFirstForm"
style
=
"display:none;"
>
<
div
class
=
"sfFormIn"
>
<
asp:Label
ID
=
"Label2"
runat
=
"server"
Text='<%$Resources:NewslettersResources, SelectAPage %>' CssClass="sfTxtLbl" />
<
sitefinity:PagesSelector
id
=
"externalPagesSelector"
runat
=
"server"
></
sitefinity:PagesSelector
>
</
div
>
</
div
>
<!-- END EXTERNAL PAGE MESSAGE -->
</
div
>
<
script
type
=
"text/javascript"
>
Sys.Application.add_load(Initialize);
function Initialize()
</
script
>
Thanks Boyan,
We are trying to add the custom meta fields to the merge tag selectors controls, however, these controls are bound by a client side service call like "~/Sitefinity/Services/Newsletters/Campaign.svc/4cbd22cc-27a7-4c52-a596-6bf968a5a431/", is there a way to extend the JS and/or the service used by this template to add items to the merge tag selectors?
I want to add a phone number field.
Where shall I put this code in custom control class. In InitializeControls method by override?
If so, it will work to create that field in db at every run.
Will it be problem? Or there is a different detail?
Hi Volkan Demirpence,
You can create the field only once, for example execute the code from a web form. First, we need to add it as a dynamic type like this:
var metaManager = Telerik.Sitefinity.Data.Metadata.MetadataManager.GetManager();
var type = metaManager.CreateMetaType(
typeof
(Subscriber));
metaManager.SaveChanges();
then we'll add the new meta field that will store the information entered in the textbox for the new field:
App.WorkWith().DynamicData().Type(
typeof
(Subscriber)).Field().TryCreateNew(
"Title"
,
typeof
(
string
)).SaveChanges(
true
);
Hello Volkan Demirpence,
Thanks for the thread, we hope to try out this method outlined here. I have a couple of follow up questions. 1) Can we dynamically create mailing lists from subscribers programatically. For example now that we have custom field 'organization' we would want to create a mailing list for only subscribers with organization = "My Org"? Can we modify the mailing list UI to do that?
2) Can you send an example of working with Campaigns programatically? We have a need to create a couple hundred campaigns with thousands of subscribers and hundreds of mailing lists that will change on dynamic data from another data source. If we can programatically manage the process that would be very helpful, so our client can then monitor their progress instead of dealing with all of the data. Thanks!
We have also added a few fields to our subscriber object. Is there a way to make these fields visible in the backend of Sitefinity?
We have also added a few fields to our subscriber object. Is there a way to make these fields visible in the backend of Sitefinity?
Hi Boyan,
I added Title and Country field using meta manager as mentioned in documentation. I can see those fields in the database but in template it does not resolve properly as mentioned in your reply. It resolves to a blank. Is there anything I am missing?
Regards,
Chaitanya.