psmb / newsletter
基于 Fusion 生成通讯
Requires
- flowpack/jobqueue-common: *
- neos/neos: ^3.0 || ^4.0
- neos/swiftmailer: *
- psmb/registry: *
- soundasleep/html2text: ~0.3
- tijsverkoyen/css-to-inline-styles: ^2.2
README
使用本包,您可以根据 Neos CMS 网站的内容(例如最新文章的摘要)生成通讯。
酷的地方在于,您可以使用 Fusion 渲染这些通讯,这允许您重用任何现有的网站 Fusion 对象,并且具有完全的灵活性。
安装
composer require "psmb/newsletter:@dev"
配置
将以下内容放入您的 Settings.yaml 中
Psmb:
Newsletter:
globalSettings:
senderAddress: 'robot@server.com'
senderName: 'Your robot'
subscriptions:
-
identifier: daily
renderer: 'Your.NameSpace:DailyLetterRenderer'
label: 'Our daily newsletter'
interval: P1D
-
identifier: weekly
renderer: 'Your.NameSpace:WeeklyLetterRenderer'
label: 'Our weekly newsletter (In Russian)'
interval: P1W
dimensions:
language: ['ru']
-
identifier: handcrafted
renderer: 'Your.NameSpace:HandcraftedDigestRenderer'
sendFromUiNodeType: 'Your.NameSpace:HandcraftedDigest'
label: 'Manually crafted newsletter'
interval: manual
您还必须在 Settings.yaml 中配置一个 baseUri
Neos:
Flow:
http:
baseUri: 'http://yourdomain.tld/'
在 Psmb.Newsletter.subscriptions 下定义您需要的订阅类型。
您可能还需要配置 SwiftMailer,请参阅其文档了解如何进行配置。
渲染通讯
如前所述,我们完全使用 Fusion 渲染信件,因此定义渲染对象完全取决于您。渲染的入口点是 newsletter = Psmb.Newsletter:SubscriptionCase
,因此您可以直接挂钩到 Psmb.Newsletter:SubscriptionCase
来拦截渲染过程。但预期的用法是通过 renderer
设置键(见上文)为每个订阅预设提供不同的渲染器。
然后为每个渲染器定义一个类似以下 Fusion 对象
prototype(Your.NameSpace:WeeklyLetterRenderer) < prototype(Psmb.Newsletter:MailRenderer) {
subject = 'Our weekly digest'
body = 'Generate message body. Use your imagination.'
# You may automatically inline all css styles.
# body.@process.cssToInline = Psmb.Newsletter:CssToInline {
# cssPath = 'resource://Your.Package/Public/Path/To/Your/Styles.css'
# }
# # You may also override these settings, but usually no need to
# format = 'plaintext' # defaults to 'html'
# recipientAddress = ${subscriber.email}
# recipientName = ${subscriber.name}
# replyToAddress = ${subscription.senderAddress || globalSettings.senderAddress}
# senderAddress = ${subscription.senderAddress || globalSettings.senderAddress}
# senderName = ${subscription.senderName || globalSettings.senderName}
}
您将可用以下上下文变量
一个更实用的例子
prototype(Sfi.Site:DigestMail) < prototype(Psmb.Newsletter:MailRenderer) {
# ElasticSearch used here, but could be a simple FlowQuery as well
@context.nodes = ${Search.query(site).nodeType('Sfi.Site:News').exactMatch('type', 'ourNews').greaterThan('date', Date.format(Date.subtract(Date.now(), subscription.interval), "Y-m-d\TH:i:sP")).sortDesc('date').execute()}
@if.notEmpty = ${q(nodes).count() > 0}
subject = ${Translation.translate('newsletter.digestSubject', null, [], null, 'Sfi.Site')}
body = Neos.Fusion:Collection {
collection = ${nodes}
itemName = 'node'
itemRenderer = Sfi.Site:DigestArticle
}
@process.cssToInline = Psmb.Newsletter:CssToInline {
cssPath = 'resource://Sfi.Site/Public/built/index.css'
}
}
prototype(Sfi.Site:DigestArticle) < prototype(Neos.Fusion:Tag) {
tagName = 'a'
attributes.href = NodeUri {
node = ${node}
absolute = ${true}
}
content = ${node.properties.title}
}
提供的 Fusion 对象
要自定义确认邮件,覆盖 Psmb.Newsletter:ConfirmationMailRenderer
。
渲染订阅插件
插入 Psmb.Newsletter:SubscriptionPlugin
nodetype 或手动渲染。
订阅流程如下
- 填写注册表单。要求提供姓名和电子邮件,并允许选择可用的订阅计划。
- 确认电子邮件。
- 编辑订阅选项或通过电子邮件链接取消订阅。
您绝对必须覆盖默认模板,默认模板仅用于演示目的。在 Configuration 中创建一个 Views.yaml
文件。
-
requestFilter: 'isPackage("Psmb.Newsletter") && isController("Subscription")'
options:
templateRootPaths:
- 'resource://Sfi.Site/Private/Newsletter/Templates/'
- 'resource://Psmb.Newsletter/Private/Templates'
partialRootPaths:
- 'resource://Sfi.Site/Private/Newsletter/Partials/'
- 'resource://Psmb.Newsletter/Private/Partials/'
layoutRootPaths:
- 'resource://Sfi.Site/Private/Newsletter/Layouts/'
发送内容
一旦您设置好订阅的渲染,就是时候发送它们了!有一个 CLI 命令可以做到这一点。
./flow newsletter:send --subscription="daily"
会向所有订阅标识为 "daily" 的订阅者发送通讯。
./flow newsletter:send --interval="P1H"
会找到所有间隔等于 "P1H" 的订阅并向它们发送信件。这对于根据时间间隔设置 cron 任务非常有用。
从 UI 手动发送
如果您的 nodetype 继承自 Psmb.Newsletter:NewsletterMixin
,您将看到一个新检查器选项卡,您可以通过它发送基于当前文档节点的手动通讯。
为此,您的至少一个订阅预设必须具有 interval: manual
。这些预设将出现在检查器视图选择框中。点击发送,该通讯就会发送给所选订阅组的所有订阅者。当前文档节点将作为 documentNode
和 node
在 Fusion 渲染器中可用。
使用作业队列提高可靠性
本包使用 flowpack/jobqueue 包生成和传递消息。请参阅其文档了解如何通过适当的作业队列实现提高其可靠性。
从 CSV 导入订阅者
创建一个包含您的订阅者数据的 CSV 文件,并将其放在您的服务器上的某个位置。
该文件应具有以下格式
"user@email.com","User Name","subscriptionId1|subscriptionId2"
"user1@email.com","User1 Name","subscriptionId2"
然后运行(文件路径相对于安装根目录)
./flow newsletter:importCsv --filename="test.csv"
这是一个如何从MySQL创建CSV导出的快速示例。
SELECT email, name INTO OUTFILE '/path/test.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM yourTable;
外部数据源
获取订阅者的默认数据源有一个标识符 Repository
。它会获取通过默认订阅插件订阅的所有订阅者。
您可以通过Json
数据源从外部JSON源获取订阅者。以下是一个示例
Psmb:
Newsletter:
subscriptions:
-
dataSourceIdentifier: 'Json'
dataSourceOptions:
uri: 'http://some.host/some-url'
或者,您可以提供自己的自定义数据源。查看JsonDataSource.php的实现,了解如何做到这一点。
还可以为数据源提供一些额外的参数,这些参数将从节点的其他属性中填充。以下是一个示例NodeTypes.yaml文件
'Psmb.Newsletter:NewsletterMixin':
abstract: true
ui:
inspector:
tabs:
newsletter:
label: i18n
position: 100
icon: icon-send
groups:
newsletter:
label: i18n
tab: newsletter
views:
newsletter:
viewOptions:
dataSourceAdditionalArguments:
sampleArgument: 'ClientEval:node.properties.sampleProperty'
properties:
sampleProperty:
type: DateTime
ui:
label: 'Subscribers since'
inspector:
group: newsletter
position: 1
editorOptions:
format: 'Y-m-d'
然后,dataSourceAdditionalArguments将被传递给数据源。您可以查看Json数据源如何处理它。
致谢
这是我第一个Flow包,没有社区的支持,特别是Christian Müller回答了Slack上成百上千个新手问题,这是不可能实现的。