Commit eab4f6d1 by Manzar Hussain

add simple news module

parent cbb8b8ac
language: php
cache:
bundler: true
directories:
- $HOME/tmp/drush
- $HOME/.bundle
apt: true
php:
- 5.4
- 5.5
notifications:
email:
- saschagros@gmail.com
- ifux@gassmann.ch
- arild@klavaro.se
env:
- PATH=$PATH:/home/travis/.composer/vendor/bin
# This will create the database
mysql:
database: drupal
username: root
encoding: utf8
# To be able to run a webbrowser
# If we need anything more powerful
# than e.g. phantomjs
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
install:
# Grab Drush
- composer global require drush/drush:dev-master --prefer-source
- cd /home/travis/.composer/vendor/drush/drush && cd -
# Make sure we don't fail when checking out projects
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
# LAMP package installation (mysql is already started)
- sudo apt-get update
- sudo apt-get install apache2 libapache2-mod-fastcgi
# enable php-fpm, travis does not support any other method with php and apache
- sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
- sudo a2enmod rewrite actions fastcgi alias
- echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
# Make sure the apache root is in our wanted directory
- echo "$(curl -fsSL https://gist.githubusercontent.com/nickveenhof/11386315/raw/b8abaf9304fe12b5cc7752d39c29c1edae8ac2e6/gistfile1.txt)" | sed -e "s,PATH,$TRAVIS_BUILD_DIR/../drupal,g" | sudo tee /etc/apache2/sites-available/default > /dev/null
# Set sendmail so drush doesn't throw an error during site install.
- echo "sendmail_path='true'" >> `php --ini | grep "Loaded Configuration" | awk '{print $4}'`
# Forward the errors to the syslog so we can print them
- echo "error_log=syslog" >> `php --ini | grep "Loaded Configuration" | awk '{print $4}'`
# Get latest drupal 8 core
- cd $TRAVIS_BUILD_DIR/..
- git clone --depth 1 --branch 8.0.x http://git.drupal.org/project/drupal.git
- cd drupal/modules
- git clone --depth 1 --branch 8.x-1.x http://git.drupal.org/project/monitoring.git
# Restart apache and test it
- sudo service apache2 restart
- curl -v "http://localhost"
# Re-enable when trying to get CodeSniffer doesn't return a 403 anymore.
#- composer global require drupal/coder:\>7
before_script:
- cd $TRAVIS_BUILD_DIR/../drupal
# Update drupal core
- git pull origin 8.0.x
# Install the site
- drush -v site-install minimal --db-url=mysql://root:@localhost/drupal --yes
- drush en --yes simpletest
- drush cr
- phpenv rehash
script:
# go to our Drupal module directory
- mkdir $TRAVIS_BUILD_DIR/../drupal/modules/simplenews
- cp -R $TRAVIS_BUILD_DIR/* $TRAVIS_BUILD_DIR/../drupal/modules/simplenews/
# go to our Drupal main directory
- cd $TRAVIS_BUILD_DIR/../drupal
- ls -la $TRAVIS_BUILD_DIR/../drupal/sites/default
# Run the tests
- php core/scripts/run-tests.sh --verbose --color --concurrency 4 --php `which php` --url http://localhost "simplenews" | tee /tmp/test.txt; TEST_EXIT=${PIPESTATUS[0]}; echo $TEST_EXIT
# Check if we had fails in the run-tests.sh script
# Exit with the inverted value, because if there are no fails found, it will exit with 1 and for us that\
# is a good thing so invert it to 0. Travis has some issues with the exclamation mark in front so we have to fiddle a
# bit.
# Also make the grep case insensitive and fail on run-tests.sh regular fails as well on fatal errors.
- TEST_OUTPUT=$(! egrep -i "([0-9]+ fails)|(PHP Fatal error)|([0-9]+ exceptions)" /tmp/test.txt > /dev/null)$?
- echo $TEST_OUTPUT
- cd $TRAVIS_BUILD_DIR/../drupal/core
- ./vendor/bin/phpunit --verbose --debug ../modules/simplenews/; TEST_PHPUNIT=$?; echo $TEST_PHPUNIT
# if the TEST_EXIT status is 0 AND the TEST_OUTPUT status is also 0 it means we succeeded, in all other cases we
# failed.
# Re-enable when trying to get CodeSniffer doesn't return a 403 anymore.
#- /home/travis/.composer/vendor/bin/phpcs --standard=/home/travis/.composer/vendor/drupal/coder/coder_sniffer/Drupal --extensions=php,inc,test,module,install --ignore=css/ $TRAVIS_BUILD_DIR/../drupal/modules/search_api
- php -i | grep 'php.ini'
- sudo cat /var/log/apache2/error.log
- sudo cat /var/log/syslog | grep 'php'
# Exit the build
- if [ $TEST_EXIT -eq 0 ] && [ $TEST_OUTPUT -eq 0 ] && [ $TEST_PHPUNIT -eq 0 ]; then exit 0; else exit 1; fi
DESCRIPTION
-----------
Simplenews publishes and sends newsletters to lists of subscribers. Both
anonymous and authenticated users can opt-in to different mailing lists.
HTML email can be sent by adding Mime mail module.
REQUIREMENTS
------------
* For large mailing lists, cron is required.
* HTML-format newsletters and/or newsletters with file attachments require the
mime mail or HMTL mail module.
* When sending newsletters on regular cron (cron.php), it is important that
the base url (settings.php, variable $base_url) is set correctly or links
inside the newsletter will not work. See the Tips (13.) below.
* Additionally when using Drush to start cron, it is important to use the
argument --uri=http://www.example.com
INSTALLATION
------------
1. CREATE DIRECTORY
Create a new directory "simplenews" in the sites/all/modules directory and
place the entire contents of this simplenews folder in it.
2. ENABLE THE MODULE
Enable the module on the Modules admin page.
3. ACCESS PERMISSION
Grant the access at the Access control page:
People > Permissions.
4. CONFIGURE SIMPLENEWS
Configure Simplenews on the Simplenews admin pages:
Configuration > Simplenews.
Enable new content types to use as newsletter:
Structure > edit content type > Publishing options
Add and configure newsletter categories:
Structure > Web Services > Newsletters > Add newsletter category
Structure > Web Services > Newsletters > edit newsletter category
5. ENABLE SIMPLENEWS BLOCK
With the Simplenews block users can subscribe to a newsletter.
Enable a Simplenews block per Newsletter category:
Structure > Newsletters > edit newsletter category
6. CONFIGURE SIMPLENEWS BLOCK
Configure the Simplenews block on the Block configuration page. You reach
this page from Block admin page (Structure > Blocks).
Click the 'Configure' link of the appropriate simplenews block.
Permission "subscribe to newsletters" is required to view the subscription
form in the simplenews block or to view the link to the subscription form.
7. SIMPLENEWS BLOCK THEMING
More control over the content of simplenews blocks can be achieved using
the block theming. Theme your simplenews block by copying
simplenews-block.html.twig into your theme directory and edit the content.
The file is self documented listing all available variables.
The newsletter block can be themed generally and per newsletter:
simplenews-block.html.twig (for all newsletters)
simplenews-block.tpl--[tid].php (for newsletter series tid)
8. MULTILINGUAL SUPPORT
Simplenews supports multilingual newsletters for node translation and url
path prefixes.
When translated newsletter issues are available subscribers receive the
newsletter in their preferred language (according to account setting).
Translation module is required for newsletter translation.
Path prefixes are added to footer message according to the subscribers
preferred language.
The preferred language of anonymous users is set based on the interface
language of the page they visit for subscription. Anonymous users can NOT
change their preferred language. Users with an account on the site will be
subscribed with the preferred language as set in their account settings.
The confirmation mails can be translated by enableding the Simplenews
variables at:
Home > Administration > Configuration > Regional and language > Multilingual settings > Variables
Afterwards, the mail subject and body can be entered for every enabled
language.
9. NEWSLETTER THEMING
You can customize the theming of newsletters. Copy the file
simplenews-newsletter-body.html.twig from the simplenews module directory
to your theme directory. Both general and by-newsletter theming can
be performed.
simplenews-newsletter-body.html.twig (for all newsletters)
simplenews-newsletter-body--[newsletter_id].html.twig
simplenews-newsletter-body--[view mode].html.twig
simplenews-newsletter-body--[newsletter_id]--[view mode].html.twig
[newsletter_id]: Machine readable name of the newsletter category
[view mode]: 'email-plain', 'email-html'
Example:
simplenews-newsletter-body--1--email-plain.html.twig
The template files are self documented listing all available variables.
Depending on how the mails are sent (e.g. how cron is triggered), either the
default or the admin theme might be used, if one has been configured.
To prevent this, Simplenews supports the mail theme setting from the
mailsystem module (http://drupal.org/project/mailsystem). Install it, choose
the mail theme and the newsletter templates from that theme will be used no
matter which other themes are enabled.
Using the fields Display settings each field of a simplenews newsletter can
be displayed or hidden in 'plain text', 'HTML' and 'HTML text alternative'
format. You find these settings at:
Structure > Content types > Manage display
Enable the view modes you want to configure and configure their display.
10. SEND MAILING LISTS
Cron is required to send large mailing lists.
If you have a medium or large size mailing list (i.e. more than 500
subscribers) always use cron to send the newsletters.
To use cron:
* Check the 'Use cron to send newsletters' checkbox.
* Set the 'Cron throttle' to the number of newsletters send per cron run.
Too high values may lead to mail server overload or you may hit hosting
restrictions. Contact your host.
Don't use cron:
* Uncheck the 'Use cron to send newsletters' checkbox.
All newsletters will be sent immediately when saving the node. If not
all emails can be sent within the available php execution time, the
remainder will be sent by cron. Therefore ALWAYS enable cron.
These settings are found on the Newsletter Settings page under
'Send mail' options at:
Administer > Configuration > Web Services > Newsletters > Settings > Send mail.
11. (UN)SUBSCRIBE CONFIRMATION
By default the unsubscribe link will direct the user to a confirmation page.
Upon confirmation the user is directed to the home page, where a message
will be displayed. On the Simplenews subscription admin page you can
specify an alternative destination page.
Structure > Configuration > Web Services > Newsletters > edit newsletter category > Subscription settings
To skip the confirmation page you can add parameters to the subscription
URL.
Example: [simplenews-subscribe-url]/ok
When an alternative destination page has been defined the extra parameters
will be added to the destination URL.
Example: [simplenews-subscriber:subscribe-url]/ok
Destination: node/123
Destination URL: node/123/ok
12. ACCESS
Every newsletter has an 'access' setting that determines whether subscribe
and unsubscribe are available on newsletter forms.
Default: Any user with 'Subscribe to newsletters' permissions can subscribe
and unsubscribe.
Hidden: Subscription is mandatory or handled programmatically by adding
manual code.
Note that mandatory subscription is restricted by law in some countries.
Moreover, note that subscribers can be added to the spool of a newsletter
issue through "Recipient Handlers" (missing documentation - see code in
RecipientHandlerInterface and examples in the demo sub-module) even when
subscribers don't have a subscription to the newsletter type corresponding
to the issue. This can be useful for the newsletter types with access set
to 'hidden'. Note that manual recipient handling is separate from manual
subscription handling — these are two separate concepts!
13. TIPS
A subscription page is available at: /newsletter/subscriptions
The Elysia Cron module (http://drupal.org/project/elysia_cron) can be used
to start the simplenews cron hook more often than others, so that newsletter
are sent faster without decreasing site performance due to long-running cron
hooks.
If your unsubscribe URL looks like:
http://newsletter/confirm/remove/8acd182182615t632
instead of:
http://www.example.com/newsletter/confirm/remove/8acd182182615t632
You should change the base URL in the settings.php file from
# $base_url = 'http://www.example.com'; // NO trailing slash!
to
$base_url = 'http://www.example.com'; // NO trailing slash!
RELATED MODULES
------------
* Elysia Cron
Allows fine grained control over cron tasks.
http://http://drupal.org/project/elysia_cron
* Mailsystem
Extends drupal core mailystem wirh Administrative UI and Developers API.
http://drupal.org/project/mailsystem
* Maillog
Captures outgoing mails, helps users debugging simplenews.
http://drupal.org/project/maillog
DOCUMENTATION
-------------
More help can be found on the help pages: example.com/admin/help/simplenews
and in the drupal.org handbook: http://drupal.org/node/197057
id: simplenews_subscriber.simplenews_subscriber.default
targetEntityType: simplenews_subscriber
bundle: simplenews_subscriber
mode: default
content:
subscriptions:
type: simplenews_subscription_select
weight: 1
settings: { }
third_party_settings: { }
mail:
type: email_default
weight: 0
settings:
placeholder: ''
third_party_settings: { }
hidden:
uid: true
status: true
dependencies:
module:
- simplenews
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenews_subscriber.account
label: Account
targetEntityType: simplenews_subscriber
cache: true
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenews_subscriber.block
label: Block
targetEntityType: simplenews_subscriber
cache: true
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenews_subscriber.page
label: Page
targetEntityType: simplenews_subscriber
cache: true
id: node.email_html
label: 'Email: HTML'
status: false
cache: true
targetEntityType: node
dependencies:
module:
- node
- simplenews
enforced:
module:
- simplenews
id: node.email_plain
label: 'Email: Plain'
status: false
cache: true
targetEntityType: node
dependencies:
module:
- node
- simplenews
enforced:
module:
- simplenews
id: default
name: 'Default newsletter'
description: 'This is an example newsletter. Change it.'
format: plain
priority: 0
receipt: TRUE
from_name: ''
subject: '[[simplenews-newsletter:name]] [node:title]'
from_address: 'replace@example.org'
hyperlinks: FALSE
allowed_handlers: { }
new_account: none
access: default
weight: 0
status: true
langcode: en
dependencies: { }
hash_expiration: 86400
newsletter:
format: plain
priority: 0
receipt: TRUE
subscriber:
sync_fields: TRUE
subscription:
skip_verification: FALSE
tidy_unconfirmed: 7
confirm_combined_subject: "Confirmation for [site:name]"
confirm_combined_body: "We have received a request for the following subscription changes for [simplenews-subscriber:mail] at [site:url]:\r\n\r\n[changes-list]\r\n\r\nTo confirm please use the link below.\r\n\r\n[simplenews-subscriber:combined-url]"
confirm_combined_body_unchanged: "We have received a request for the following subscription changes for [simplenews-subscriber:mail] at [site:url]:\r\n\r\n[changes-list]\r\n\r\nNo confirmation necessary because all requested changes equal the current state."
confirm_combined_line_subscribe_unsubscribed: "Subscribe to [simplenews-newsletter:name]"
confirm_combined_line_subscribe_subscribed: "Already subscribed to [simplenews-newsletter:name]"
confirm_combined_line_unsubscribe_subscribed: "Unsubscribe from [simplenews-newsletter:name]"
confirm_combined_line_unsubscribe_unsubscribed: "Already unsubscribed from [simplenews-newsletter:name]"
confirm_subscribe_page: ""
confirm_unsubscribe_page: ""
mail:
use_cron: TRUE
textalt: FALSE
throttle: 20
spool_progress_expiration: 3600
spool_expire: 0
debug: FALSE
id: simplenews_send_action
label: 'Send newsletter issue'
status: true
langcode: en
type: node
plugin: simplenews_send_action
id: simplenews_stop_action
label: 'Stop sending'
status: true
langcode: en
type: node
plugin: simplenews_stop_action
langcode: en
status: true
dependencies:
config:
- field.field.node.simplenews_issue.body
- field.field.node.simplenews_issue.simplenews_issue
- node.type.simplenews_issue
module:
- options
- text
id: node.simplenews_issue.default
targetEntityType: node
bundle: simplenews_issue
mode: default
content:
body:
type: text_textarea_with_summary
weight: 2
settings:
rows: 9
summary_rows: 3
placeholder: ''
third_party_settings: { }
created:
type: datetime_timestamp
weight: 10
settings: { }
third_party_settings: { }
promote:
type: boolean_checkbox
settings:
display_label: true
weight: 15
third_party_settings: { }
simplenews_issue:
type: simplenews_issue
weight: 3
settings: { }
third_party_settings: { }
sticky:
type: boolean_checkbox
settings:
display_label: true
weight: 16
third_party_settings: { }
title:
type: string_textfield
weight: 0
settings:
size: 60
placeholder: ''
third_party_settings: { }
uid:
type: entity_reference_autocomplete
weight: 5
settings:
match_operator: CONTAINS
size: 60
placeholder: ''
match_limit: 10
third_party_settings: { }
hidden: { }
langcode: en
status: true
dependencies:
config:
- field.field.node.simplenews_issue.body
- field.field.node.simplenews_issue.simplenews_issue
- node.type.simplenews_issue
module:
- text
- user
id: node.simplenews_issue.default
targetEntityType: node
bundle: simplenews_issue
mode: default
content:
body:
type: text_default
weight: 0
label: hidden
settings: { }
third_party_settings: { }
links:
weight: 1
settings: { }
third_party_settings: { }
hidden:
simplenews_issue: true
uuid: 595d84b8-78d5-46b1-855d-93f466a736b9
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.email_html
- field.field.node.simplenews_issue.body
- field.field.node.simplenews_issue.simplenews_issue
- node.type.simplenews_issue
module:
- text
- user
id: node.simplenews_issue.email_html
targetEntityType: node
bundle: simplenews_issue
mode: email_html
content:
body:
type: text_default
weight: 0
settings: { }
third_party_settings: { }
label: hidden
hidden:
simplenews_issue: true
links: true
third_party_settings: { }
uuid: a836de9a-6d1f-4ed7-8600-fbc2b09286c1
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.email_plain
- field.field.node.simplenews_issue.body
- field.field.node.simplenews_issue.simplenews_issue
- node.type.simplenews_issue
module:
- text
- user
id: node.simplenews_issue.email_plain
targetEntityType: node
bundle: simplenews_issue
mode: email_plain
content:
body:
type: text_default
weight: 0
settings: { }
third_party_settings: { }
label: hidden
hidden:
simplenews_issue: true
links: true
third_party_settings: { }
uuid: 1754e700-7290-485d-a404-4a052ef18ae2
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.teaser
- field.field.node.simplenews_issue.body
- field.field.node.simplenews_issue.simplenews_issue
- node.type.simplenews_issue
module:
- text
- user
id: node.simplenews_issue.teaser
label: null
targetEntityType: node
bundle: simplenews_issue
mode: teaser
content:
body:
type: text_trimmed
weight: 0
settings:
trim_length: 600
third_party_settings: { }
label: hidden
hidden:
langcode: true
simplenews_issue: true
links: true
third_party_settings: { }
id: node.simplenews_issue.body
status: true
langcode: en
field_name: body
entity_type: node
bundle: simplenews_issue
label: Body
description: ''
required: false
translatable: false
default_value: { }
default_value_callback: ''
settings:
display_summary: false
third_party_settings: { }
field_type: text_with_summary
dependencies:
config:
- field.storage.node.body
- node.type.simplenews_issue
module:
- text
langcode: en
status: true
dependencies:
config:
- field.storage.node.simplenews_issue
- node.type.simplenews_issue
module:
- simplenews
id: node.simplenews_issue.simplenews_issue
field_name: simplenews_issue
entity_type: node
bundle: simplenews_issue
label: Newsletter
description: ''
required: true
translatable: true
default_value:
-
target_id: default
handler: simplenews_all
handler_settings: { }
status: 0
sent_count: 0
error_count: 0
subscribers: 0
default_value_callback: ''
settings:
handler: default
handler_settings:
target_bundles: null
field_type: simplenews_issue
id: simplenews_issue
status: true
langcode: und
field_name: simplenews_issue
entity_type: node
type: simplenews_issue
settings:
target_type: simplenews_newsletter
module: simplenews
locked: false
cardinality: 1
indexes: { }
dependencies:
module:
- simplenews
id: simplenews_pending
label: 'Simplenews spool size'
description: 'Pending items in the simplenews spool.'
category: Simplenews
plugin_id: simplenews_pending
value_label: 'Pending items'
status: FALSE
dependencies:
module:
- simplenews
type: simplenews_issue
name: Newsletter Issue
description: 'Use <em>Newsletter Issue</em> for newsletters.'
help: ''
preview_mode: 1
display_submitted: false
status: true
new_revision: false
langcode: en
dependencies: { }
langcode: en
status: true
dependencies:
module:
- simplenews
title: 'Sends newsletters'
id: simplenews_cron
module: simplenews
callback: simplenews_cron
scheduler:
id: simple
configuration:
rules:
- '*/5+@ * * * *'
launcher:
id: serial
configuration:
timeouts:
lock_timeout: 3600
max_execution_time: 3600
launcher:
max_threads: 1
logger:
id: database
configuration:
method: '3'
expire: 1209600
retain: 1000
# Settings schema.
simplenews.settings:
type: config_object
label: 'Simplenews settings'
mapping:
hash_expiration:
type: integer
label: Hash expiration
newsletter:
type: mapping
label: Newsletter settings
mapping:
format:
type: string
label: Default format for new newsletters
priority:
type: integer
label: Default priority for new newsletters
receipt:
type: boolean
label: Default require receipt setting for newsletters
from_address:
type: string
label: Default from email address
from_name:
type: label
label: Default from name
subscriber:
type: mapping
mapping:
sync_fields:
type: boolean
label: Sync between account and subscriber fields
subscription:
type: mapping
label: Subscription settings
mapping:
skip_verification:
type: boolean
label: Skip verification for anonymous users
tidy_unconfirmed:
type: integer
label: Tidy unconfirmed subscriptions after a number of days
confirm_combined_subject:
type: label
label: Combined subscribe subject
confirm_combined_body:
type: text
label: Combined subscribe message
confirm_combined_body_unchanged:
type: text
label: Combined subscribe unchanged message
confirm_combined_line_subscribe_unsubscribed:
type: label
label: Combined subscribe message
confirm_combined_line_subscribe_subscribed:
type: label
label: Combined already subscribed message
confirm_combined_line_unsubscribe_subscribed:
type: label
label: Combined unsubscribe message
confirm_combined_line_unsubscribe_unsubscribed:
type: label
label: Combined already unsubscribed message
confirm_subscribe_page:
type: string
label: Confirmation subscribe redirect page
confirm_unsubscribe_page:
type: string
label: Confirmation unsubscribe redirect page
mail:
type: mapping
label: Mail settings
mapping:
use_cron:
type: boolean
label: Use cron
textalt:
type: boolean
label: Generate plain-text alternative
throttle:
type: integer
label: Mails to send per cron run
spool_progress_expiration:
type: integer
label: Spool in progress expiration
spool_expire:
type: integer
label: Expiration of sent mails in spool
debug:
type: boolean
label: Debug
# Newsletter config entity schema.
simplenews.newsletter.*:
type: config_entity
label: 'Newsletter'
mapping:
name:
type: label
label: 'Name'
id:
type: string
label: 'Machine-readable name'
description:
type: text
label: 'Description of the newsletter'
format:
type: string
label: 'HTML or plaintext newsletter indicator'
priority:
type: integer
label: 'Priority indicator'
receipt:
type: boolean
label: 'TRUE if a read receipt should be requested.'
from_name:
type: label
label: 'Name of the email author.'
subject:
type: label
label: 'Subject of newsletter email. May contain tokens.'
from_address:
type: string
label: 'Email author address'
hyperlinks:
type: boolean
label: 'Indicates if hyperlinks should be kept inline or extracted.'
allowed_handlers:
type: sequence
label: 'Restricts which recipient handlers are allowed.'
sequence:
type: string
label: Allowed recipient handler
new_account:
type: string
label: 'Indicates how to integrate with the register form.'
access:
type: string
label: 'Controls access to subscribe and unsubscribe.'
weight:
type: integer
label: 'Weight of this newsletter (used for sorting).'
field.simplenews_subscription.settings:
type: mapping
label: 'Subscription settings'
mapping:
target_type:
type: string
label: 'Type of item to reference'
field.simplenews_subscription.instance_settings:
type: mapping
label: 'Subscription settings'
mapping:
handler:
type: string
label: 'Reference method'
handler_settings:
type: entity_reference.[%parent.handler].handler_settings
label: 'Reference method settings'
# Monitoring schema.
monitoring.settings.simplenews_pending:
type: monitoring.settings_base
label: 'Simplenews pending sensor settings'
mapping: { }
# Simplenews issue field type schema.
field.storage_settings.simplenews_issue:
type: field.storage_settings.entity_reference
label: 'Simplenews issue settings'
mapping: { }
field.field_settings.simplenews_issue:
type: field.field_settings.entity_reference
label: 'Simplenews issue settings'
field.value.simplenews_issue:
type: field.value.entity_reference
label: 'Default value'
mapping:
handler:
type: string
label: Handler
handler_settings:
type: mapping
label: Handler settings
status:
type: integer
label: Sent status
sent_count:
type: integer
label: Sent count
error_count:
type: integer
label: Error count
subscribers:
type: integer
label: Subscriber count
# Simplenews suscription field type schema.
field.storage_settings.simplenews_subscription:
type: field.storage_settings.entity_reference
label: 'Simplenews subscription settings'
mapping: { }
field.field_settings.simplenews_subscription:
type: field.field_settings.entity_reference
label: 'Simplenews subscription settings'
field.value.simplenews_subscription:
type: field.value.entity_reference
label: 'Default value'
mapping: { }
# Block schema
block.settings.simplenews_subscription_block:
type: block_settings
mapping:
newsletters:
type: sequence
label: Newsletters
sequence:
type: string
label: Newsletter ID
message:
type: label
label: Message
unique_id:
type: string
label: Unique ID
action.configuration.simplenews_send_action:
type: action_configuration_default
label: 'Send selected newsletter issue'
action.configuration.simplenews_stop_action:
type: action_configuration_default
label: 'Stop selected newsletter issue'
views.field.subscriber_link_delete:
type: views_field
label: 'Subscriber delete link'
mapping:
text:
type: label
label: 'Text to display'
views.field.subscriber_link_edit:
type: views_field
label: 'Subscriber edit link'
mapping:
text:
type: label
label: 'Text to display'
views.field.simplenews_user_name:
type: views_field
label: 'Username field'
mapping:
text:
type: label
label: 'Text to display'
build:
assessment:
validate_codebase:
phplint:
container_composer:
csslint:
eslint:
phpcs:
testing:
run_tests.standard:
types: 'Simpletest,PHPUnit-Unit,PHPUnit-Kernel,PHPUnit-Functional'
# Test for Drupal 9 compatibility
suppress-deprecations: false
run_tests.js:
concurrency: 1
types: 'PHPUnit-FunctionalJavascript'
# Test for Drupal 9 compatibility
suppress-deprecations: false
nightwatchjs:
services:
simplenews.commands:
class: \Drupal\simplenews\Commands\SimplenewsCommands
arguments: ['@config.factory', '@simplenews.spool_storage', '@simplenews.mailer']
tags:
- { name: drush.command }
id: d7_simplenews_issue
dependencies:
module:
- simplenews
label: Simplenews issues
migration_tags:
- Drupal 7
- Content
source:
plugin: simplenews_issue
process:
nid: nid
simplenews_issue/target_id:
plugin: migration_lookup
migration: d7_simplenews_newsletter
source: tid
simplenews_issue/handler:
plugin: default_value
default_value: 'simplenews_all'
simplenews_issue/handler_settings:
plugin: default_value
default_value: []
simplenews_issue/status: status
simplenews_issue/sent_count: sent_subscriber_count
simplenews_issue/error_count:
plugin: default_value
default_value: 0
simplenews_issue/subscribers: sent_subscriber_count
destination:
plugin: entity:node
destination_module: simplenews
migration_dependencies:
required:
- d7_node
- d7_simplenews_newsletter
id: d7_simplenews_newsletter
dependencies:
module:
- simplenews
label: Simplenews newsletters
migration_tags:
- Drupal 7
- Content
source:
plugin: simplenews_newsletter
process:
name: name
id:
plugin: machine_name
source: name
description: description
format: format
priority: priority
receipt: receipt
from_name: from_name
subject: email_subject
from_address: from_address
hyperlinks: hyperlinks
new_account: new_account
access:
-
plugin: static_map
source: opt_inout
map:
double: default
single: default
hidden: hidden
weight: weight
destination:
plugin: entity:simplenews_newsletter
destination_module: simplenews
id: d7_simplenews_subscriber
dependencies:
module:
- simplenews
label: Simplenews subscribers
migration_tags:
- Drupal 7
- Content
source:
plugin: simplenews_subscriber
process:
id: snid
status: activated
mail: mail
uid: uid
langcode: language
changes: changes
created: created
subscriptions:
plugin: iterator
source: subscriptions
process:
target_id:
plugin: migration_lookup
migration: d7_simplenews_newsletter
source: newsletter_id
status: status
timestamp: timestamp
source: source
destination:
plugin: entity:simplenews_subscriber
destination_module: simplenews
migration_dependencies:
required:
- d7_simplenews_newsletter
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenewssubscription
theme: bartik
region: sidebar_first
weight: -7
provider: null
plugin: simplenews_subscription_block
settings:
id: simplenews_subscription_block
label: 'Simplenews subscription'
provider: simplenews
label_display: visible
newsletters:
default: default
message: 'Stay informed - subscribe to our newsletter.'
unique_id: dbbcae7b-bb10-4cf8-8c3d-61e4990109b5
visibility: { }
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenewssubscription_all
theme: bartik
region: sidebar_first
weight: -7
provider: null
plugin: simplenews_subscription_block
settings:
id: simplenews_subscription_block
label: 'Simplenews multiple subscriptions'
provider: simplenews
label_display: visible
newsletters:
weekly_content_update: weekly_content_update
special_offers: special_offers
press_releases: press_releases
default: default
message: 'Stay informed - subscribe to our newsletters.'
unique_id: d74b88af-9f36-4c5b-8122-34538c6b172c
visibility: { }
langcode: en
status: true
dependencies:
config:
- field.storage.simplenews_subscriber.field_city
id: simplenews_subscriber.simplenews_subscriber.field_city
field_name: field_city
entity_type: simplenews_subscriber
bundle: simplenews_subscriber
label: City
description: ''
required: false
translatable: false
default_value:
-
value: ''
default_value_callback: ''
settings: { }
field_type: string
langcode: en
status: true
dependencies:
config:
- field.storage.simplenews_subscriber.field_first_name
id: simplenews_subscriber.simplenews_subscriber.field_first_name
field_name: field_first_name
entity_type: simplenews_subscriber
bundle: simplenews_subscriber
label: 'First name'
description: ''
required: false
translatable: false
default_value:
-
value: ''
default_value_callback: ''
settings: { }
field_type: string
langcode: en
status: true
dependencies:
config:
- field.storage.simplenews_subscriber.field_last_name
id: simplenews_subscriber.simplenews_subscriber.field_last_name
field_name: field_last_name
entity_type: simplenews_subscriber
bundle: simplenews_subscriber
label: 'Last name'
description: ''
required: false
translatable: false
default_value:
-
value: ''
default_value_callback: ''
settings: { }
field_type: string
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenews_subscriber.field_city
field_name: field_city
entity_type: simplenews_subscriber
type: string
settings:
max_length: 50
case_sensitive: false
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenews_subscriber.field_first_name
field_name: field_first_name
entity_type: simplenews_subscriber
type: string
settings:
max_length: 50
case_sensitive: false
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
langcode: en
status: true
dependencies:
module:
- simplenews
id: simplenews_subscriber.field_last_name
field_name: field_last_name
entity_type: simplenews_subscriber
type: string
settings:
max_length: 50
case_sensitive: false
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
id: press_releases
name: 'Press releases'
description: 'This is the press release.'
format: plain
priority: 0
receipt: false
from_name: ''
subject: '[[simplenews-newsletter:name]] [node:title]'
from_address: 'replace@example.org'
hyperlinks: true
allowed_handlers: { }
new_account: none
access: default
weight: 0
status: true
langcode: en
dependencies: { }
id: special_offers
name: 'Special offers'
description: 'Special offers newsletter.'
format: plain
priority: 0
receipt: false
from_name: ''
subject: '[[simplenews-newsletter:name]] [node:title]'
from_address: 'replace@example.org'
hyperlinks: true
allowed_handlers: { }
new_account: none
access: default
weight: 0
status: true
langcode: en
dependencies: { }
id: weekly_content_update
name: 'Weekly content update'
description: 'Weekly content update newsletter.'
format: plain
priority: 0
receipt: false
from_name: ''
subject: '[[simplenews-newsletter:name]] [node:title]'
from_address: 'replace@example.org'
hyperlinks: true
allowed_handlers: { }
new_account: none
access: default
weight: 0
status: true
langcode: en
dependencies: { }
name: Simplenews Demo
type: module
description: Demo module for Simplenews.
core_version_requirement: ^8.8 || ^9
dependencies:
- drupal:block
- drupal:views
- simplenews:simplenews
# - simplenews_scheduler:simplenews_scheduler
hidden: false
package: Mail
# Information added by Drupal.org packaging script on 2020-10-19
version: '3.0.0-alpha1'
project: 'simplenews'
datestamp: 1603102795
<?php
/**
* @file
* Simplenews_demo base install file.
*/
use Drupal\node\Entity\Node;
use Drupal\simplenews\Entity\Newsletter;
use Drupal\simplenews\Entity\Subscriber;
use Drupal\user\Entity\User;
/**
* Implements hook_install().
*
* Declares initial configuration for simplenews_demo.
*/
function simplenews_demo_install() {
\Drupal::service('router.builder')->rebuild();
// Set the default values for test_address, from_address and from_name.
$site_mail = \Drupal::config('system.site')->get('mail');
$site_name = \Drupal::config('system.site')->get('name');
// Init the demo newsletter.
$newsletters = Newsletter::loadMultiple();
foreach ($newsletters as $newsletter) {
$newsletter->from_name = $site_name;
$newsletter->from_address = $site_mail;
$newsletter->save();
}
// Add subscriber fields to the form display.
\Drupal::service('entity_display.repository')->getFormDisplay('simplenews_subscriber', 'simplenews_subscriber')
->setComponent('field_first_name', [
'type' => 'string_textfield',
'weight' => '2',
'settings' => [
'size' => 60,
'placeholder' => '',
],
'third_party_settings' => [],
])
->setComponent('field_last_name', [
'type' => 'string_textfield',
'weight' => '3',
'settings' => [
'size' => 60,
'placeholder' => '',
],
'third_party_settings' => [],
])
->setComponent('field_city', [
'type' => 'string_textfield',
'weight' => '4',
'settings' => [
'size' => 60,
'placeholder' => '',
],
'third_party_settings' => [],
])
->save();
/** @var \Drupal\simplenews\Subscription\SubscriptionManagerInterface $subscription_manager */
$subscription_manager = \Drupal::service('simplenews.subscription_manager');
// Create some subscribers.
// Subscriber subscribed to only one newsletter.
$subscription_manager->subscribe('a@example.com', $newsletters['special_offers']->id(), FALSE);
$subscriber = Subscriber::loadByMail('a@example.com');
// Add field data for subscriber.
$subscriber->set('field_first_name', 'Subscriber A first name');
$subscriber->set('field_last_name', 'Subscriber A last name');
$subscriber->set('field_city', 'Subscriber A city');
$subscriber->save();
// Subscriber subscribed to all newsletters.
$subscription_manager->subscribe('b@example.com', $newsletters['special_offers']->id(), FALSE);
$subscription_manager->subscribe('b@example.com', $newsletters['press_releases']->id(), FALSE);
$subscription_manager->subscribe('b@example.com', $newsletters['weekly_content_update']->id(), FALSE);
// Add field data to subscriber.
$subscriber = Subscriber::loadByMail('a@example.com');
$subscriber->set('field_first_name', 'Subscriber B first name');
$subscriber->save();
// Unsubscribed subscriber.
$subscription_manager->subscribe('c@example.com', $newsletters['press_releases']->id(), FALSE);
$subscription_manager->unsubscribe('c@example.com', $newsletters['press_releases']->id(), FALSE);
// Unconfirmed subscriber.
$subscription_manager->subscribe('d@example.com', $newsletters['special_offers']->id(), TRUE);
// Create an active demo user.
$demo_user_active = User::create([
'name' => 'demo user 1',
'mail' => 'demouser1@example.com',
'status' => TRUE,
]);
$demo_user_active->activate();
$demo_user_active->save();
// Create a blocked demo user.
$demo_user_blocked = User::create([
'name' => 'demo user 2',
'mail' => 'demouser2@example.com',
'status' => FALSE,
]);
$demo_user_blocked->block();
$demo_user_blocked->save();
// Create an inactive subscriber.
$subscriber_inactive = Subscriber::create([
'mail' => 'd@example.com',
'status' => FALSE,
]
);
$subscriber_inactive->save();
// Subscribe user to both newsletters.
$subscription_manager->subscribe($demo_user_active->getEmail(), $newsletters['press_releases']->id(), FALSE);
$subscription_manager->subscribe($demo_user_active->getEmail(), $newsletters['special_offers']->id(), FALSE);
// Create an issue for scheduled sending.
// Disabled because of issue #3062330.
// @codingStandardsIgnoreStart
// $scheduled_issue = Node::create(array(
// 'type' => 'simplenews_issue',
// 'id' => 'simplenews_issue_scheduled',
// 'title' => 'Scheduled weekly content newsletter issue',
// 'body' => 'Scheduled weekly content newsletter issue will be sent to subscribers every week',
// 'created' => time(),
// 'uid' => 0,
// 'status' => 1,
// 'simplenews_issue' => array(
// 'target_id' => 'weekly_content_update',
// 'handler' => 'simplenews_all',
// 'handler_settings' => array()
// ),
// ));
// $scheduled_issue->save();
// // Write a record for the demo newsletter scheduler configuration.
// $nid = $scheduled_issue->id();
// $record = array(
// 'nid' => $nid,
// 'next_run' => strtotime('yesterday, 8:00 UTC'),
// 'activated' => 1,
// 'send_interval' => 'week',
// 'interval_frequency' => 1,
// 'start_date' => strtotime('yesterday, 8:00 UTC'),
// 'stop_type' => 0,
// 'stop_date' => 0,
// 'stop_edition' => 0,
// 'title' => '[node:title] - [node:created:custom:\W\e\e\k W,Y ]',
// );
// // Update scheduler record.
// \Drupal::database()->merge('simplenews_scheduler')
// ->key(array(
// 'nid' => $nid,
// ))
// ->fields($record)
// ->execute();
// @codingStandardsIgnoreEnd
// A newsletter to send.
$spool_storage = \Drupal::service('simplenews.spool_storage');
$node = Node::create([
'type' => 'simplenews_issue',
'id' => 'simplenews_issue_sent',
'title' => 'Sent press releases',
'body' => 'This press release is already sent to subscribers!',
'uid' => 0,
'status' => 1,
'simplenews_issue' => [
'target_id' => 'press_releases',
'handler' => 'simplenews_all',
'handler_settings' => [],
],
]);
$node->save();
// Send the node.
$spool_storage->addIssue($node);
// Send mails.
\Drupal::service('simplenews.mailer')->sendSpool();
// Run cron.
\Drupal::service('cron')->run();
// Update send status of newsletter issues.
\Drupal::service('simplenews.mailer')->updateSendStatus();
// Create a newsletter issues with different send status.
// Published newsletter, not yet sent.
$node = Node::create([
'type' => 'simplenews_issue',
'id' => 'simplenews_issue_pending',
'title' => 'Pending special offers',
'body' => 'Grab them while you can, limited availability! These offers can often only be available for a short time, so take advantage of these special prices while you can.',
'uid' => 0,
'status' => 1,
'simplenews_issue' => [
'target_id' => 'special_offers',
'handler' => 'simplenews_all',
'handler_settings' => [],
],
]);
$node->save();
$spool_storage->addIssue($node);
// Unpublished newsletter.
$node = Node::create([
'type' => 'simplenews_issue',
'id' => 'simplenews_issue_unpublished',
'title' => 'Unpublished press releases',
'body' => 'Unpublished press releases body',
'uid' => 0,
'status' => 0,
'simplenews_issue' => [
'target_id' => 'press_releases',
'handler' => 'simplenews_all',
'handler_settings' => [],
],
]);
$node->save();
$spool_storage->addIssue($node);
// Newsletter that is stopped sending.
$node = Node::create([
'type' => 'simplenews_issue',
'id' => 'simplenews_issue_stopped',
'title' => 'Stopped special offers',
'body' => 'Upcoming special offers!',
'uid' => 0,
'status' => 1,
'simplenews_issue' => [
'target_id' => 'special_offers',
'handler' => 'simplenews_all',
'handler_settings' => [],
],
]);
$node->save();
}
<?php
namespace Drupal\simplenews_demo\Plugin\simplenews\RecipientHandler;
use Drupal\simplenews\Plugin\simplenews\RecipientHandler\RecipientHandlerEntityBase;
/**
* This handler sends to all active users that have never logged in.
*
* @RecipientHandler(
* id = "simplenews_new_users",
* title = @Translation("New users")
* )
*/
class RecipientHandlerNewUsers extends RecipientHandlerEntityBase {
/**
* {@inheritdoc}
*/
protected function buildEntityQuery() {
return \Drupal::entityQuery('user')
->exists('mail')
->condition('access', 0)
->condition('status', TRUE);
}
/**
* {@inheritdoc}
*/
protected function cacheCount() {
return TRUE;
}
}
<?php
namespace Drupal\simplenews_demo\Plugin\simplenews\RecipientHandler;
use Drupal\simplenews\Plugin\simplenews\RecipientHandler\RecipientHandlerBase;
/**
* Recipient Handler that sends to the main site mail.
*
* @RecipientHandler(
* id = "simplenews_site_mail",
* title = @Translation("Send to main site mail")
* )
*/
class RecipientHandlerSiteMail extends RecipientHandlerBase {
/**
* {@inheritdoc}
*/
public function addToSpool() {
$subscriber_data = ['mail' => \Drupal::config('system.site')->get('mail')];
$this->addArrayToSpool('data', [$subscriber_data]);
return 1;
}
/**
* {@inheritdoc}
*/
protected function doCount() {
return 1;
}
}
<?php
namespace Drupal\simplenews_demo\Plugin\simplenews\RecipientHandler;
use Drupal\simplenews\SubscriberInterface;
use Drupal\simplenews\Plugin\simplenews\RecipientHandler\RecipientHandlerEntityBase;
/**
* This handler sends to all subscribers with the specified role.
*
* @RecipientHandler(
* id = "simplenews_subscribers_by_role",
* title = @Translation("Subscribers by role")
* )
*/
class RecipientHandlerSubscribersByRole extends RecipientHandlerEntityBase {
/**
* {@inheritdoc}
*/
public function settingsForm() {
$roles = array_map(['\Drupal\Component\Utility\Html', 'escape'], user_role_names(TRUE));
$element['role'] = [
'#type' => 'select',
'#title' => t('Role'),
'#default_value' => $this->configuration['role'] ?? NULL,
'#options' => $roles,
];
return $element;
}
/**
* {@inheritdoc}
*/
protected function buildEntityQuery() {
return \Drupal::entityQuery('simplenews_subscriber')
->condition('status', SubscriberInterface::ACTIVE)
->condition('subscriptions', $this->getNewsletterId())
->condition('subscriptions.status', SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED)
->condition('uid.entity.roles', $this->configuration['role']);
}
}
<?php
namespace Drupal\Tests\simplenews_demo\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the demo module for Simplenews.
*
* @group simplenews
*/
class SimplenewsDemoTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var string[]
*/
public static $modules = [];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'classy';
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Install bartik theme.
\Drupal::service('theme_installer')->install(['bartik']);
$theme_settings = $this->config('system.theme');
$theme_settings->set('default', 'bartik')->save();
// Install simplenews_demo module.
\Drupal::service('module_installer')->install(['simplenews_demo']);
// Log in with all relevant permissions.
$this->drupalLogin($this->drupalCreateUser([
'administer simplenews subscriptions', 'send newsletter', 'administer newsletters', 'administer simplenews settings',
]));
}
/**
* Asserts the demo module has been installed successfully.
*/
public function testInstalled() {
// Check for the two subscription blocks.
$this->assertText('Simplenews multiple subscriptions');
$this->assertText('Stay informed - subscribe to our newsletters.');
$this->assertText('Simplenews subscription');
$this->assertText('Stay informed - subscribe to our newsletter.');
$this->drupalGet('admin/config/services/simplenews');
$this->clickLink(t('Edit'));
// Assert default description is present.
$this->assertEquals('This is an example newsletter. Change it.', $this->xpath('//textarea[@id="edit-description"]')[0]->getText());
$from_name = $this->xpath('//input[@id="edit-from-name"]')[0];
$from_address = $this->xpath('//input[@id="edit-from-address"]')[0];
$this->assertEquals('Drupal', (string) $from_name->getValue());
$this->assertEquals('simpletest@example.com', (string) $from_address->getValue());
// Assert demo newsletters.
$this->drupalGet('admin/config/services/simplenews');
$this->assertText(t('Press releases'));
$this->assertText(t('Special offers'));
$this->assertText(t('Weekly content update'));
// Assert demo newsletters sent.
$this->drupalGet('admin/content/simplenews');
// @codingStandardsIgnoreLine
//$this->assertText('Scheduled weekly content newsletter issue');
$this->assertText('Sent press releases');
$this->assertText('Unpublished press releases');
$this->assertText('Pending special offers');
$this->assertText('Stopped special offers');
// @codingStandardsIgnoreLine
//$this->assertText('Scheduled weekly content newsletter issue - Week ');
$this->assertRaw(t('Newsletter issue sent to 2 subscribers, 0 errors.'));
$this->assertRaw(t('Newsletter issue is pending, 0 mails sent out of 3, 0 errors.'));
// Weekly newsletter.
// @codingStandardsIgnoreLine
//$this->assertRaw(t('Newsletter issue sent to 1 subscribers, 0 errors.'));
// Assert demo subscribers.
$this->drupalGet('admin/people/simplenews');
$this->assertText('a@example.com');
$this->assertText('b@example.com');
$this->assertText('demouser1@example.com');
}
}
<?php
/**
* @file
* Hooks provided by the Simplenews module.
*/
use Drupal\simplenews\Entity\Newsletter;
use Drupal\simplenews\Entity\Subscriber;
use Drupal\simplenews\Spool\SpoolStorageInterface;
use Drupal\simplenews\SubscriberInterface;
/**
* Simplenews builds on the following basic concepts.
*
* @link subscriber Subscribers @endlink subscribe to @link newsletter
* newsletters (categories) @endlink. That connection is called
* a @link subscription subscription @endlink. Nodes of enabled content types
* are @link issue newsletter issues @endlink. These are then sent to the
* subscribers of the newsletter the issue is attached to.
*
* Sending is done by first adding a row for each subscriber to the @link spool
* mail spool @endlink.
* Then they are processed either immediatly or during cron runs. The actual
* sending happens through a @link source source instance @endlink, which is
* first instanciated based on the mail spool and then used to generated the
* actual mail content.
*
* @mainpage Simplenews API documentation.
*/
/**
* @defgroup subscriber Subscriber
*
* @todo
*/
/**
* @defgroup newsletter (category)
*
* @todo
*/
/**
* @defgroup subscription Subscription
*
* @todo
*/
/**
* @defgroup issue Newsletter issue
*
* @todo
*/
/**
* @defgroup spool Mail spool
*
* @todo
*/
/**
* @defgroup source Source
*
* @todo
*/
/**
* Return operations to be applied to newsletter issues.
*
* @ingroup issue
*/
function hook_simplenews_issue_operations() {
$operations = [
'activate' => [
'label' => t('Send'),
'callback' => 'simplenews_issue_send',
],
];
return $operations;
}
/**
* Return operations to be applied to subscriptions.
*
* @ingroup issue
*/
function hook_simplenews_subscription_operations() {
$operations = [
'activate' => [
'label' => t('Activate'),
'callback' => 'simplenews_subscription_activate',
'callback arguments' => [SubscriberInterface::ACTIVE],
],
'inactivate' => [
'label' => t('Inactivate'),
'callback' => 'simplenews_subscription_activate',
'callback arguments' => [SubscriberInterface::INACTIVE],
],
'delete' => [
'label' => t('Delete'),
'callback' => 'simplenews_subscription_delete_multiple',
],
];
return $operations;
}
/**
* Act after a newsletter category has been saved.
*
* @param \Drupal\simplenews\Entity\Newsletter $newsletter
* The newsletter object.
*
* @ingroup newsletter
*/
function hook_simplenews_newsletter_update(Newsletter $newsletter) {
}
/**
* Act after a newsletter category has been deleted.
*
* @param \Drupal\simplenews\Entity\Newsletter $newsletter
* The newsletter object.
*
* @ingroup newsletter
*/
function hook_simplenews_newsletter_delete(Newsletter $newsletter) {
}
/**
* Act after a newsletter category has been inserted.
*
* @param \Drupal\simplenews\Entity\Newsletter $newsletter
* The newsletter object.
*
* @ingroup newsletter
*/
function hook_simplenews_newsletter_insert(Newsletter $newsletter) {
}
/**
* Act after a subscriber is updated.
*
* @param \Drupal\simplenews\Entity\Subscriber $subscriber
* The subscriber object including all subscriptions of this user.
*
* @ingroup subscriber
*/
function hook_simplenews_subscriber_update(Subscriber $subscriber) {
}
/**
* Act after a new subscriber has been created.
*
* @param \Drupal\simplenews\Entity\Subscriber $subscriber
* The subscriber object including all subscriptions of this user.
*
* @ingroup subscriber
*/
function hook_simplenews_subscriber_insert(Subscriber $subscriber) {
}
/**
* Act after a subscriber has been deleted.
*
* @param \Drupal\simplenews\Entity\Subscriber $subscriber
* The subscriber object including all subscriptions of this user.
*
* @ingroup subscriber
*/
function hook_simplenews_subscriber_delete(Subscriber $subscriber) {
}
/**
* Invoked if a subscriber is subscribed to a newsletter.
*
* @param \Drupal\simplenews\Entity\Subscriber $subscriber
* The subscriber object including all subscriptions of this user.
* @param string $subscription
* The subscription object for this specific subscribe action.
*
* @ingroup subscriber
*/
function hook_simplenews_subscribe_user(Subscriber $subscriber, $subscription) {
}
/**
* Invoked if a subscriber is unsubscribed from a newsletter.
*
* @param \Drupal\simplenews\Entity\Subscriber $subscriber
* The subscriber object including all subscriptions of this user.
* @param string $subscription
* The subscription object for this specific unsubscribe action.
*
* @ingroup subscriber
*/
function hook_simplenews_unsubscribe(Subscriber $subscriber, $subscription) {
}
/**
* Expose SimplenewsSource cache implementations.
*
* @return array
* An array keyed by the name of the class that provides the implementation,
* the array value consists of another array with the keys label and
* description.
*
* @ingroup source
*/
function hook_simplenews_source_cache_info() {
return [
'SimplenewsSourceCacheNone' => [
'label' => t('No caching'),
'description' => t('This allows to theme each newsletter separately.'),
],
'SimplenewsSourceCacheBuild' => [
'label' => t('Cached content source'),
'description' => t('This caches the rendered content to be sent for multiple recipients. It is not possible to use subscriber specific theming but tokens can be used for personalization.'),
],
];
}
/**
* Invoked after sending of every mail to allow altering of the result.
*
* A common use of this hook is categorise errors and distinguish a global
* failure from an error that is specific to a single recipient.
*
* @param int $result
* One of the SpoolStorageInterface::STATUS_* constants.
* @param array $message
* The message returned by \Drupal\Core\Mail\MailManagerInterface::mail().
*/
function hook_simplenews_mail_result_alter(&$result, array $message) {
if (specific_error()) {
$result = SpoolStorageInterface::STATUS_FAILED;
}
if (global_error()) {
throw new AbortSendingException('Mail transport error');
}
}
simplenews.settings:
title: 'Simplenews settings'
base_route_name: simplenews.newsletter_list
names:
- simplenews.settings
<?php
/**
* @file
* Drush commands for administer Simplenews.
*/
use Drupal\simplenews\Spool\SpoolStorageInterface;
/**
* Implements hook_drush_command().
*/
function simplenews_drush_command() {
$items = [];
$items['simplenews-spool-count'] = [
'description' => 'Print the current simplenews mail spool count',
'aliases' => ['sn-sc'],
'drupal dependencies' => ['simplenews'],
'options' => [
'pipe' => dt('Just print the count value to allow parsing'),
],
];
$items['simplenews-spool-send'] = [
'description' => 'Send the defined amount of mail spool entries.',
'examples' => [
'drush sn-ss' => dt('Send the default amount of mails, as defined by the mail.throttle settings.'),
'drush sn-ss 0' => dt('Send all mails.'),
'drush sn-ss 100' => dt('Send 100 mails.'),
],
'options' => [
'limit' => dt('Number of mails to send. 0 sends all emails. If not specified, will be set to the value of the mail.throttle in the module settings config.'),
'pipe' => dt('Just print the sent and remaining count on separate lines to allow parsing'),
],
'aliases' => ['sn-ss'],
'drupal dependencies' => ['simplenews'],
];
return $items;
}
/**
* Drush command to count the mail spool queue.
*/
function drush_simplenews_spool_count() {
$count = \Drupal::service('simplenews.spool_storage')->countMails();
$no_description = drush_get_option(['p', 'pipe']);
if ($no_description) {
drush_print_pipe($count);
}
else {
\Drupal::logger('simplenews')->status('Current simplenews mail spool count: @count', ['@count' => $count]);
}
}
/**
* Drush command to send the mail spool queue.
*/
function drush_simplenews_spool_send($limit = FALSE) {
if (!simplenews_assert_uri()) {
drush_set_error('Site URI not specified, use --uri.');
return;
}
if ($limit === FALSE) {
$limit = \Drupal::config('simplenews.settings')->get('mail.throttle');
}
elseif ($limit == 0) {
$limit = SpoolStorageInterface::UNLIMITED;
}
$start_time = microtime(TRUE);
$sent = \Drupal::service('simplenews.mailer')->sendSpool($limit);
\Drupal::service('simplenews.spool_storage')->clear();
\Drupal::service('simplenews.mailer')->updateSendStatus();
$durance = round(microtime(TRUE) - $start_time, 2);
// Report the number of sent mails.
if ($sent > 0) {
$remaining = \Drupal::service('simplenews.spool_storage')->countMails();
if (drush_get_option(['p', 'pipe'])) {
// For pipe, print the sent first and then the remaining count, separated
// by a space.
drush_print_pipe($sent . " " . $remaining);
}
else {
\Drupal::logger('simplenews')->status('Sent @count mails from the queue in @sec seconds.', ['@count' => $sent, '@sec' => $durance]);
\Drupal::logger('simplenews')->status('Remaining simplenews mail spool count: @count', ['@count' => $remaining]);
}
}
}
name: Simplenews
description: 'Send newsletters to subscribed email addresses. For uninstall go to Configuration > Web services > Simplenews > Settings and hit "Prepare uninstall".'
type: module
package: Mail
core_version_requirement: ^8.8 || ^9
dependencies:
- drupal:node
- drupal:field
- drupal:options
- drupal:views
test_dependencies:
- monitoring:monitoring
configure: simplenews.newsletter_list
# Information added by Drupal.org packaging script on 2020-10-19
version: '3.0.0-alpha1'
project: 'simplenews'
datestamp: 1603102795
simplenews.newsletter_add:
route_name: simplenews.newsletter_add
title: 'Add newsletter'
appears_on:
- simplenews.newsletter_list
simplenews.subscriber_add:
route_name: entity.simplenews_subscriber.add_form
title: 'Add subscriber'
appears_on:
- entity.simplenews_subscriber.collection
simplenews.newsletter_issue_add:
route_name: node.add
appears_on:
- view.simplenews_newsletters.page_1
deriver: 'Drupal\simplenews\Plugin\Derivative\AddSimplenewsIssueActionLinks'
simplenews.settings:
title: Simplenews
description: 'Configure your sites newsletters.'
parent: system.admin_config_services
route_name: simplenews.newsletter_list
simplenews.subscriber_settings:
title: Subscriber settings
description: 'Administer your subscriber settings.'
parent: user.admin_index
route_name: simplenews.settings_subscriber
simplenews.subscribers:
title: Subscribers
description: 'Administer your subscribers.'
parent: entity.user.collection
route_name: entity.simplenews_subscriber.collection
simplenews.newsletters:
title: Newsletter issues
description: 'Find and manage newsletter issues.'
parent: system.admin_content
route_name: view.simplenews_newsletters.page_1
simplenews.settings_subscriber:
title: Settings
description: 'Simplenews subscriber settings.'
base_route: simplenews.settings_subscriber
route_name: simplenews.settings_subscriber
simplenews.newsletter_list:
title: Newsletters
description: 'Listing of all newsletters.'
base_route: simplenews.newsletter_list
route_name: simplenews.newsletter_list
simplenews.settings:
title: Settings
description: 'Simplenews settings.'
base_route: simplenews.newsletter_list
route_name: simplenews.settings_newsletter
simplenews.settings_newsletter:
title: Newsletter
description: 'Simplenews newsletter settings.'
base_route: simplenews.newsletter_list
route_name: simplenews.settings_newsletter
parent_id: simplenews.settings
weight: -15
simplenews.settings_subscription:
title: Subscription
description: 'Subscription settings, opt-in/out confirmation email text.'
base_route: simplenews.newsletter_list
route_name: simplenews.settings_subscription
parent_id: simplenews.settings
weight: -10
simplenews.settings_mail:
title: 'Send mail'
description: 'Send mail, cron and debug options.'
base_route: simplenews.newsletter_list
route_name: simplenews.settings_mail
parent_id: simplenews.settings
weight: -5
simplenews.settings_prepare_uninstall:
title: 'Prepare uninstall'
description: 'Remove fields and data created by Simplenews module.'
base_route: simplenews.newsletter_list
route_name: simplenews.settings_prepare_uninstall
parent_id: simplenews.settings
weight: -4
simplenews.newsletter_subscriptions_user:
title: Newsletters
description: 'Configure your newsletter subscriptions.'
base_route: entity.user.canonical
route_name: simplenews.newsletter_subscriptions_user
simplenews.node_tab:
title: Newsletter
route_name: simplenews.node_tab
base_route: entity.node.canonical
weight: 5
entity.simplenews_subscriber.collection:
title: 'Subscribers'
route_name: entity.simplenews_subscriber.collection
base_route: entity.user.collection
weight: 15
simplenews.subscribers_sub:
title: 'List'
route_name: entity.simplenews_subscriber.collection
parent_id: entity.simplenews_subscriber.collection
simplenews.subscriber_import:
title: 'Mass subscribe'
route_name: simplenews.subscriber_import
parent_id: entity.simplenews_subscriber.collection
simplenews.subscriber_unsubscribe:
title: 'Mass unsubscribe'
route_name: simplenews.subscriber_unsubscribe
parent_id: entity.simplenews_subscriber.collection
simplenews.subscriber_export:
title: 'Export'
route_name: simplenews.subscriber_export
parent_id: entity.simplenews_subscriber.collection
administer newsletters:
title: 'Administer newsletters'
administer simplenews subscriptions:
title: 'Administer simplenews subscriptions'
view simplenews subscriptions:
title: 'View simplenews subscriptions'
administer simplenews settings:
title: 'Administer simplenews settings'
send newsletter:
title: 'Send newsletter'
subscribe to newsletters:
title: 'Subscribe to newsletters'
simplenews.settings_newsletter:
path: '/admin/config/services/simplenews/settings/newsletter'
defaults:
_form: '\Drupal\simplenews\Form\NewsletterSettingsForm'
_title: 'Newsletter'
requirements:
_permission: 'administer simplenews settings'
simplenews.settings_subscriber:
path: '/admin/config/people/simplenews/settings/subscriber'
defaults:
_form: '\Drupal\simplenews\Form\SubscriberSettingsForm'
_title: 'Subscriber'
requirements:
_permission: 'administer simplenews settings'
simplenews.settings_subscription:
path: '/admin/config/services/simplenews/settings/subscription'
defaults:
_form: '\Drupal\simplenews\Form\SubscriptionSettingsForm'
_title: 'Subscription'
requirements:
_permission: 'administer simplenews settings'
simplenews.settings_mail:
path: '/admin/config/services/simplenews/settings/mail'
defaults:
_form: '\Drupal\simplenews\Form\MailSettingsForm'
_title: 'Send mail'
requirements:
_permission: 'administer simplenews settings'
simplenews.settings_prepare_uninstall:
path: '/admin/config/services/simplenews/settings/uninstall'
defaults:
_form: '\Drupal\simplenews\Form\PrepareUninstallForm'
_title: 'Prepare uninstall'
requirements:
_permission: 'administer simplenews settings'
simplenews.newsletter_list:
path: '/admin/config/services/simplenews'
defaults:
_entity_list: 'simplenews_newsletter'
_title: 'Simplenews'
requirements:
_permission: 'administer newsletters'
simplenews.newsletter_add:
path: '/admin/config/services/simplenews/add'
defaults:
_entity_form: 'simplenews_newsletter.add'
_title: 'Add newsletter'
requirements:
_entity_create_access: 'simplenews_newsletter'
entity.simplenews_newsletter.edit_form:
path: '/admin/config/services/simplenews/manage/{simplenews_newsletter}'
defaults:
_entity_form: 'simplenews_newsletter.edit'
_title: 'Edit newsletter'
requirements:
_entity_access: 'simplenews_newsletter.update'
entity.simplenews_newsletter.delete_form:
path: '/admin/config/services/simplenews/manage/{simplenews_newsletter}/delete'
defaults:
_entity_form: 'simplenews_newsletter.delete'
_title: 'Delete'
requirements:
_entity_access: 'simplenews_newsletter.delete'
entity.simplenews_subscriber.collection:
path: /admin/people/simplenews
defaults:
_entity_list: 'simplenews_subscriber'
_title: 'Subscribers'
requirements:
_permission: 'administer simplenews subscriptions'
entity.simplenews_subscriber.add_form:
path: '/admin/people/simplenews/create'
defaults:
_entity_form: 'simplenews_subscriber.add'
_title: 'Add subscriber'
requirements:
_entity_create_access: 'simplenews_subscriber'
entity.simplenews_subscriber.edit_form:
path: '/admin/people/simplenews/edit/{simplenews_subscriber}'
defaults:
_entity_form: 'simplenews_subscriber.default'
_title: 'Edit subscriber'
requirements:
_entity_access: 'simplenews_subscriber.update'
entity.simplenews_subscriber.delete_form:
path: '/admin/people/simplenews/delete/{simplenews_subscriber}'
defaults:
_entity_form: 'simplenews_subscriber.delete'
_title: 'Delete'
requirements:
_entity_access: 'simplenews_subscriber.delete'
simplenews.subscriber_import:
path: '/admin/people/simplenews/import'
defaults:
_form: '\Drupal\simplenews\Form\SubscriberMassSubscribeForm'
_title: 'Mass subscribe'
requirements:
_permission: 'administer simplenews subscriptions'
simplenews.subscriber_unsubscribe:
path: '/admin/people/simplenews/unsubscribe'
defaults:
_form: '\Drupal\simplenews\Form\SubscriberMassUnsubscribeForm'
_title: 'Mass unsubscribe'
requirements:
_permission: 'administer simplenews subscriptions'
simplenews.subscriber_export:
path: '/admin/people/simplenews/export'
defaults:
_form: '\Drupal\simplenews\Form\SubscriberExportForm'
_title: 'Export'
requirements:
_permission: 'administer simplenews subscriptions'
simplenews.newsletter_subscriptions:
path: '/newsletter/subscriptions'
defaults:
_entity_form: 'simplenews_subscriber.page'
_title: 'Your newsletter subscriptions'
requirements:
_permission: 'subscribe to newsletters'
simplenews.newsletter_subscriptions_arguments:
path: '/newsletter/subscriptions/{snid}/{timestamp}/{hash}'
defaults:
_entity_form: 'simplenews_subscriber.page'
_title: 'Your newsletter subscriptions'
requirements:
_permission: 'subscribe to newsletters'
simplenews.newsletter_subscriptions_user:
path: '/user/{user}/simplenews'
defaults:
_entity_form: 'simplenews_subscriber.account'
_title: 'Newsletters'
requirements:
_custom_access: 'Drupal\simplenews\Form\SubscriptionsAccountForm::checkAccess'
options:
parameters:
user:
type: entity:user
# The next 4 confirmation routes have no access check because the access is
# verified by the hash. It's not good UX to force a user to login in order to
# unsubscribe.
simplenews.newsletter_confirm_combined:
path: '/newsletter/confirm/combined/{snid}/{timestamp}/{hash}'
defaults:
_controller: '\Drupal\simplenews\Controller\ConfirmationController::confirmCombined'
_title: 'Confirm newsletter subscriptions'
requirements:
_access: 'TRUE'
options:
no_cache: TRUE
simplenews.newsletter_confirm_subscription:
path: '/newsletter/confirm/{action}/{snid}/{newsletter_id}/{timestamp}/{hash}'
defaults:
_controller: '\Drupal\simplenews\Controller\ConfirmationController::confirmSubscription'
_title: 'Confirm newsletter subscriptions'
requirements:
_access: 'TRUE'
options:
no_cache: TRUE
simplenews.newsletter_confirm_combined_immediate:
path: '/newsletter/confirm/combined/{snid}/{timestamp}/{hash}/ok'
defaults:
_controller: '\Drupal\simplenews\Controller\ConfirmationController::confirmCombined'
_title: 'Confirm newsletter subscriptions'
immediate: true
requirements:
_access: 'TRUE'
options:
no_cache: TRUE
simplenews.newsletter_confirm_subscription_immediate:
path: '/newsletter/confirm/{action}/{snid}/{newsletter_id}/{timestamp}/{hash}/ok'
defaults:
_controller: '\Drupal\simplenews\Controller\ConfirmationController::confirmSubscription'
_title: 'Confirm newsletter subscriptions'
immediate: true
requirements:
_access: 'TRUE'
options:
no_cache: TRUE
simplenews.node_tab:
path: '/node/{node}/simplenews'
defaults:
_form: '\Drupal\simplenews\Form\NodeTabForm'
_title: 'Newsletter'
requirements:
_custom_access: 'Drupal\simplenews\Form\NodeTabForm::checkAccess'
options:
_admin_route: true
no_cache: TRUE
services:
plugin.manager.simplenews_recipient_handler:
class: Drupal\simplenews\RecipientHandler\RecipientHandlerManager
parent: default_plugin_manager
simplenews.spool_storage:
class: Drupal\simplenews\Spool\SpoolStorage
arguments: ['@database', '@lock', '@config.factory', '@module_handler', '@plugin.manager.simplenews_recipient_handler']
logger.channel.simplenews:
parent: logger.channel_base
arguments: ['simplenews']
simplenews.mailer:
class: Drupal\simplenews\Mail\Mailer
arguments: ['@simplenews.spool_storage', '@plugin.manager.mail', '@state', '@logger.channel.simplenews', '@account_switcher', '@lock', '@config.factory', '@entity_type.manager', '@language_manager', '@simplenews.mail_cache', '@module_handler']
simplenews.mail_builder:
class: Drupal\simplenews\Mail\MailBuilder
arguments: ['@token', '@config.factory', '@simplenews.subscription_manager']
simplenews.subscription_manager:
class: Drupal\simplenews\Subscription\SubscriptionManager
arguments: ['@language_manager', '@config.factory', '@simplenews.mailer', '@token', '@logger.channel.simplenews', '@current_user']
tags:
- { name: needs_destruction }
simplenews.mail_cache:
class: Drupal\simplenews\Mail\MailCacheBuild
simplenews.migration_subscriber:
class: Drupal\simplenews\EventSubscriber\MigrationSubscriber
arguments: ['@entity_field.manager', '@entity_display.repository']
tags:
- { name: event_subscriber }
<?php
/**
* @file
* Token related hook implementations.
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Url;
/**
* Implements hook_token_info().
*/
function simplenews_token_info() {
$types['simplenews-subscriber'] = [
'name' => t('Simplenews subscriber'),
'description' => t('Tokens related to the newsletter recipient'),
'needs-data' => 'simplenews_subscriber',
];
$types['simplenews-newsletter'] = [
'name' => t('Simplenews newsletter'),
'description' => t('Tokens related to the newsletter'),
'needs-data' => 'newsletter',
];
// Tokens for simplenews subscriber.
$subscriber['subscribe-url'] = [
'name' => t('Subscription URL'),
'description' => t('The URL of the page where the subscription is confirmed.'),
];
$subscriber['unsubscribe-url'] = [
'name' => t('Unsubscribe URL'),
'description' => t('The URL of the page where the cancellation of the subscription is confirmed.'),
];
$subscriber['manage-url'] = [
'name' => t('Manage URL'),
'description' => t('The URL of the page where the subscribers can manage their newsletter subscriptions.'),
];
$subscriber['combined-url'] = [
'name' => t('Combined confirmation URL'),
'description' => t('The URL of the page where subscribers can confirm their subscription changes.'),
];
$subscriber['mail'] = [
'name' => t('Subscriber email'),
'description' => t('The email address of the newsletter receiver.'),
];
$subscriber['user'] = [
'name' => t('Corresponding user'),
'description' => t('The user object that corresponds to this subscriber. This is not set for anonymous subscribers.'),
'type' => 'user',
];
// Tokens for simplenews newsletter.
$newsletter['name'] = [
'name' => t('Newsletter'),
'description' => t('The name of the newsletter.'),
];
$newsletter['url'] = [
'name' => t('Newsletter URL'),
'description' => t('The URL of the page listing the issues of this newsletter.'),
];
return [
'types' => $types,
'tokens' => [
'simplenews-subscriber' => $subscriber,
'simplenews-newsletter' => $newsletter,
],
];
}
/**
* Implements hook_tokens().
*/
function simplenews_tokens($type, $tokens, $data, $options, BubbleableMetadata $bubbleable_metadata) {
$replacements = [];
$sanitize = !empty($options['sanitize']);
switch ($type) {
case 'simplenews-subscriber':
if (!isset($data['simplenews_subscriber'])) {
return;
}
/** @var \Drupal\simplenews\Entity\Subscriber $subscriber */
$subscriber = $data['simplenews_subscriber'];
$newsletter = isset($data['newsletter']) ? $data['newsletter'] : NULL;
$language = $subscriber->getLangcode();
$url_arguments = ['absolute' => TRUE, 'langcode' => $language];
foreach ($tokens as $name => $original) {
$route_parameters = ['snid' => $subscriber->id(), 'timestamp' => REQUEST_TIME];
switch ($name) {
case 'subscribe-url':
$hash = simplenews_generate_hash($subscriber->getMail(), 'add');
$bubbleable_metadata->setCacheMaxAge(0);
$route_parameters += [
'action' => 'add',
'newsletter_id' => $newsletter->id(),
'hash' => $hash,
];
$replacements[$original] = Url::fromRoute('simplenews.newsletter_confirm_subscription', $route_parameters, $url_arguments)->toString();
break;
case 'unsubscribe-url':
if (!$subscriber->id()) {
// Temporary test subscriber.
$replacements[$original] = t('No unsubscribe link for test subscribers.');
break;
}
$hash = simplenews_generate_hash($subscriber->getMail(), 'remove');
$bubbleable_metadata->setCacheMaxAge(0);
$route_parameters += [
'action' => 'remove',
'newsletter_id' => $newsletter->id(),
'hash' => $hash,
];
$replacements[$original] = Url::fromRoute('simplenews.newsletter_confirm_subscription', $route_parameters, $url_arguments)->toString();
break;
case 'combined-url':
$hash = simplenews_generate_hash($subscriber->getMail(), 'combined' . serialize($subscriber->getChanges()));
$bubbleable_metadata->setCacheMaxAge(0);
$route_parameters += ['hash' => $hash];
$replacements[$original] = Url::fromRoute('simplenews.newsletter_confirm_combined', $route_parameters, $url_arguments)->toString();
break;
case 'manage-url':
$hash = simplenews_generate_hash($subscriber->getMail(), 'manage');
$bubbleable_metadata->setCacheMaxAge(0);
$route_parameters += ['hash' => $hash];
$replacements[$original] = Url::fromRoute('simplenews.newsletter_subscriptions_arguments', $route_parameters, $url_arguments)->toString();
break;
case 'mail':
$replacements[$original] = Html::escape($subscriber->getMail());
break;
}
}
if (($user_tokens = \Drupal::token()->findWithPrefix($tokens, 'user')) && !empty($subscriber->uid)) {
$replacements += \Drupal::token()->generate('user', $user_tokens, ['user' => $subscriber->getUser()], $options, $bubbleable_metadata);
}
break;
case 'simplenews-newsletter':
if (!isset($data['newsletter'])) {
return;
}
$newsletter = $data['newsletter'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'name':
if (isset($newsletter->name)) {
$replacements[$original] = $sanitize ? Html::escape($newsletter->name) : $newsletter->name;
}
else {
$replacements[$original] = t('Unassigned newsletter');
}
break;
case 'url':
$replacements[$original] = $newsletter->url();
break;
}
}
break;
}
return $replacements;
}
<?php
/**
* @file
* Views interface for simplenews.
*/
use Drupal\field\FieldStorageConfigInterface;
/**
* Implements hook_field_views_data().
*/
function simplenews_field_views_data(FieldStorageConfigInterface $field_storage) {
$data = views_field_default_views_data($field_storage);
foreach ($data as $table_name => $table_data) {
// Add the filter for newsletters.
$data[$table_name][$field_storage->getName() . '_target_id']['filter']['id'] = 'in_operator';
$data[$table_name][$field_storage->getName() . '_target_id']['filter']['options callback'] = 'simplenews_newsletter_list';
}
return $data;
}
/**
* Implements hook_views_data().
*/
function simplenews_views_data() {
$data['node']['send_status'] = [
'real field' => 'nid',
'field' => [
'title' => t('Send status'),
'help' => t('Send status of the newsletter.'),
'id' => 'simplenews_send_status',
],
'group' => t('Content'),
];
/* ------------ Definitions for Simplenews mailspool ---------------------- */
$data['simplenews_mail_spool']['table'] = [
'base' => [
'field' => 'msid',
'title' => t('Simplenews mailspool'),
'help' => t('Spool for temporary storage of newsletter emails.'),
'weight' => 10,
'database' => 'default',
],
'group' => t('Simplenews spool'),
];
$data['simplenews_mail_spool']['msid'] = [
'title' => t('Ms ID'),
'help' => t('The primary identifier for a mail spool record.'),
'field' => [
'id' => 'numeric',
'click sortable' => TRUE,
],
'filter' => [
'id' => 'numeric',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'numeric',
],
'sort' => [
'id' => 'standard',
],
];
$data['simplenews_mail_spool']['entity_id'] = [
'title' => t('Node ID'),
'help' => t('The {node}.nid of this newsletter.'),
'field' => [
'id' => 'numeric',
'click sortable' => TRUE,
],
'filter' => [
'id' => 'numeric',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'numeric',
],
'sort' => [
'id' => 'standard',
],
'relationship' => [
'id' => 'standard',
'base' => 'node',
'base field' => 'nid',
'label' => t('Node'),
],
];
$data['simplenews_mail_spool']['newsletter_id'] = [
'title' => t('Newsletter ID'),
'help' => t('The newsletter_id this newsletter issue belongs to.'),
'field' => [
'id' => 'numeric',
'click sortable' => TRUE,
],
'filter' => [
'id' => 'numeric',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'numeric',
],
'sort' => [
'id' => 'standard',
],
'relationship' => [
'id' => 'standard',
'base' => 'simplenews_newsletter',
'base field' => 'newsletter_id',
'label' => t('Newsletter'),
],
];
$data['simplenews_mail_spool']['snid'] = [
'title' => t('Subscriber ID'),
'help' => t('The {simplenews_subscriber}.snid foreign key for this spool'),
'field' => [
'id' => 'numeric',
'click sortable' => TRUE,
],
'filter' => [
'id' => 'numeric',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'numeric',
],
'sort' => [
'id' => 'standard',
],
'relationship' => [
'id' => 'standard',
'base' => 'simplenews_subscriber',
'base field' => 'snid',
'label' => t('Subscriber'),
],
];
$data['simplenews_mail_spool']['status'] = [
'title' => t('Sent status'),
'help' => t('The sent status of the email (0 = hold, 1 = pending, 2 = done, 3 = in progress, 4 = skipped, 5 = failed).'),
'field' => [
'id' => 'numeric',
'click sortable' => TRUE,
],
'filter' => [
'id' => 'numeric',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'numeric',
],
'sort' => [
'id' => 'standard',
],
];
$data['simplenews_mail_spool']['timestamp'] = [
'title' => t('Timestamp'),
'help' => t('The time status was set or changed.'),
'field' => [
'id' => 'date',
'click sortable' => TRUE,
],
'filter' => [
'id' => 'date',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'date',
],
'sort' => [
'id' => 'date',
],
];
$data['simplenews_mail_spool']['data'] = [
'title' => t('Data'),
'help' => t('A serialized array of name value pairs that define a temporary subscriber.'),
'field' => [
'id' => 'standard',
'click sortable' => TRUE,
],
'filter' => [
'id' => 'string',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'string',
],
'sort' => [
'id' => 'standard',
],
];
return $data;
}
name = Simplenews rules
description = Provides integration with Rules module for Simplenews.
dependencies[] = simplenews
dependencies[] = rules
package = Mail
core = 7.x
; Information added by Drupal.org packaging script on 2020-10-19
version = "3.0.0-alpha1"
project = "simplenews"
datestamp = "1603102795"
<?php
/**
* @file
* Module file for Simplenews rules integration.
*/
use Drupal\simplenews\Entity\Newsletter;
define('SIMPLENEWS_RULES_CONFIRMATION_DEFAULT', 0);
define('SIMPLENEWS_RULES_CONFIRMATION_YES', 1);
define('SIMPLENEWS_RULES_CONFIRMATION_NO', 2);
/**
* Returns the options for the confirmation paramter.
*/
function simplenews_rules_confirmation_list() {
return array(
SIMPLENEWS_RULES_CONFIRMATION_DEFAULT => t('Default'),
SIMPLENEWS_RULES_CONFIRMATION_YES => t('Yes'),
SIMPLENEWS_RULES_CONFIRMATION_NO => t('No'),
);
}
/**
* Implements hook_simplenews_unsubscribe().
*/
function simplenews_rules_simplenews_unsubscribe($subscriber, $subscription) {
$args = array(
'mail' => $subscriber->mail,
'newsletter' => Newsletter::load($subscription->newsletter_id),
);
rules_invoke_event_by_args('simplenews_rules_event_unsubscribe', $args);
}
/**
* Implements hook_simplenews_subscribe().
*/
function simplenews_rules_simplenews_subscribe($subscriber, $subscription) {
$args = array(
'mail' => $subscriber->mail,
'newsletter' => Newsletter::load($subscription->newsletter_id),
);
rules_invoke_event_by_args('simplenews_rules_event_subscribe', $args);
}
<?php
/**
* @file
* Rules hooks for the Simplenews newsletter module.
*
* @addtogroup rules
* @{
*/
use Drupal\simplenews\Entity\Subscriber;
/**
* Implements hook_rules_action_info().
*/
function simplenews_rules_rules_action_info() {
return array(
'simplenews_rules_action_send' => array(
'label' => t('Send newsletter'),
'group' => t('Simplenews'),
'parameter' => array(
'node' => array(
'type' => 'node',
'label' => t('The newsletter node to be sent.'),
'description' => t('The newsletter node that should be sent.'),
),
),
),
'simplenews_rules_action_subscribe' => array(
'label' => t('Subscribe an e-mail adress to a newsletter'),
'group' => t('Simplenews'),
'named parameter' => TRUE,
'parameter' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that should be subscribed.'),
),
'newsletter_id' => array(
'type' => 'integer',
'label' => t('Simplenews newsletter'),
'descrption' => t('For which newsletter the subscription should happen.'),
'options list' => 'simplenews_newsletter_list',
),
'confirmation' => array(
'type' => 'integer',
'label' => t('Confirmation required'),
'description' => t('Select if a confirmation is required. Default uses the default setting from the chosen newsletter.'),
'options list' => 'simplenews_rules_confirmation_list',
'default value' => SIMPLENEWS_RULES_CONFIRMATION_DEFAULT,
),
'source' => array(
'type' => 'string',
'label' => t('Source'),
'description' => t('A string to identify the source of this subscription'),
'optional' => TRUE,
),
'source' => array(
'type' => 'text',
'label' => t('Source'),
'description' => t('A string to identify the source of this subscription'),
'optional' => TRUE,
'default value' => 'rules',
),
'language' => array(
'type' => 'token',
'label' => t('Language'),
'description' => t('If specified, the language to use for the subscription. Defaults to the default language.'),
'options list' => 'entity_metadata_language_list',
'optional' => TRUE,
'default value' => LANGUAGE_NONE,
),
),
),
'simplenews_rules_action_unsubscribe' => array(
'label' => t('Unsubscribe an e-mail adress from a newsletter'),
'group' => t('Simplenews'),
'named parameter' => TRUE,
'parameter' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that should be unsubscribed.'),
),
'newsletter' => array(
'type' => 'simplenews_newsletter',
'label' => t('Simplenews newsletter'),
'descrption' => t('For which newsletter the subscription should happen.'),
'options list' => 'simplenews_newsletter_list',
),
'confirmation' => array(
'type' => 'integer',
'label' => t('Confirmation required'),
'description' => t('Select if a confirmation is required. Default uses the default setting from the chosen newsletter.'),
'options list' => 'simplenews_rules_confirmation_list',
'default value' => SIMPLENEWS_RULES_CONFIRMATION_DEFAULT,
),
'source' => array(
'type' => 'text',
'label' => t('Source'),
'description' => t('A string to identify the source of this subscription'),
'optional' => TRUE,
'default value' => 'rules',
),
'language' => array(
'type' => 'token',
'label' => t('Language'),
'description' => t('If specified, the language to use for the subscription. Defaults to the default language.'),
'options list' => 'entity_metadata_language_list',
'optional' => TRUE,
'default value' => LANGUAGE_NONE,
),
),
),
'simplenews_rules_action_subscription_delete' => array(
'label' => t('Delete an e-mail address from a newsletter'),
'group' => t('Simplenews'),
'named parameter' => TRUE,
'parameter' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that should be permanently deleted from the newsletter. Note, use the unsubscribe action to temporarily unsubscribe an email address.'),
),
'newsletter' => array(
'type' => 'simplenews_newsletter',
'label' => t('Simplenews newsletter'),
'descrption' => t('For which newsletter the subscription should happen.'),
),
),
),
'simplenews_rules_action_subscriber_delete' => array(
'label' => t('Delete an e-mail address from all newsletters'),
'group' => t('Simplenews'),
'named parameter' => TRUE,
'parameter' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that should be permanently deleted from all newsletters. Note, use the unsubscribe action to temporarily unsubscribe an email address.'),
),
),
),
);
}
/**
* Implements hook_event_info().
*/
function simplenews_rules_rules_event_info() {
return array(
'simplenews_rules_event_subscribe' => array(
'label' => t('A user has been subscribed'),
'group' => t('Simplenews'),
'variables' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-Mail'),
'description' => t('The e-mail address that has been subscribed.'),
),
'newsletter' => array(
'type' => 'simplenews_newsletter',
'label' => t('Simplenews newsletter'),
'descrption' => t('For which newsletter the subscription should happen.'),
),
),
),
'simplenews_rules_event_unsubscribe' => array(
'label' => t('A user has been unsubscribed'),
'group' => t('Simplenews'),
'variables' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that has been subscribed.'),
),
'newsletter' => array(
'type' => 'simplenews_newsletter',
'label' => t('Simplenews newsletter'),
'descrption' => t('For which newsletter the subscription should happen.'),
),
),
),
);
}
/**
* Action implementation, send a newsletter node.
*/
function simplenews_rules_action_send($node) {
\Drupal::service('simplenews.spool_storage')->addIssue($node);
}
/**
* Action Implementation: Subscribe an e-mail adress to a Simplenews newsletter.
*/
function simplenews_rules_action_subscribe($args, $settings) {
if ($args['language'] == LANGUAGE_NONE) {
$args['language'] = NULL;
}
$confirmation = simplenews_rules_map_confirmation($args);
// Pass the call forward.
\Drupal::service('simplenews.subscription_manager')->subscribe($args['mail'], $args['tid'], $confirmation, $args['source'], $args['language']);
}
/**
* Action Implementation: Unsubscribe an e-mail adress to a newsletter.
*/
function simplenews_rules_action_unsubscribe($args, $settings) {
if ($args['language'] == LANGUAGE_NONE) {
$args['language'] = NULL;
}
$confirmation = simplenews_rules_map_confirmation($args);
// Pass the call forward.
\Drupal::service('simplenews.subscription_manager')->unsubscribe($args['mail'], $args['tid'], $confirmation, $args['source'], $args['language']);
}
/**
* Action Implementation: Delete an email address from a specific newsletter.
*/
function simplenews_rules_action_subscription_delete($args, $settings) {
if (!empty($args['mail']) && !empty($args['tid'])) {
\Drupal::entityTypeManager()->getStorage('simplenews_subscriber')->deleteSubscriptions(array('mail' => $args['mail'], 'tid' => $args['tid']));
}
}
/**
* Action Implementation: Delete an email address from all newsletters.
*/
function simplenews_rules_action_subscriber_delete($args, $settings) {
if ($subscriber = Subscriber::loadByMail($args['mail'])) {
$subscriber->delete();
}
}
/**
* Map args to the confrmation argument for subscribing/unsubscribing.
*/
function simplenews_rules_map_confirmation($args) {
switch ($args['confirmation']) {
case SIMPLENEWS_RULES_CONFIRMATION_YES:
$confirmation = TRUE;
break;
case SIMPLENEWS_RULES_CONFIRMATION_NO:
$confirmation = FALSE;
break;
case SIMPLENEWS_RULES_CONFIRMATION_DEFAULT:
$confirmation = NULL;
break;
}
return $confirmation;
}
/**
* @}
*/
<?php
namespace Drupal\simplenews;
/**
* Exception to throw to abort the current batch of sending.
*
* Use this when there is a global transport error that means any attempt to
* send to any address will fail.
*/
class AbortSendingException extends \RuntimeException {
}
<?php
namespace Drupal\simplenews\Commands;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\simplenews\Mail\MailerInterface;
use Drupal\simplenews\Spool\SpoolStorageInterface;
use Drush\Commands\DrushCommands;
use Psr\Log\LogLevel;
/**
* A Drush commandfile.
*
* In addition to this file, you need a drush.services.yml
* in root of your module, and a composer.json file that provides the name
* of the services file to use.
*
* See these files for an example of injecting Drupal services:
* - http://cgit.drupalcode.org/devel/tree/src/Commands/DevelCommands.php
* - http://cgit.drupalcode.org/devel/tree/drush.services.yml
*/
class SimplenewsCommands extends DrushCommands {
/**
* The simplenews config.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $simplenewsConfig;
/**
* The spool storage.
*
* @var \Drupal\simplenews\Spool\SpoolStorageInterface
*/
protected $spoolStorage;
/**
* The mailer service.
*
* @var \Drupal\simplenews\Mail\MailerInterface
*/
protected $mailer;
/**
* SimplenewsCommands constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\simplenews\Spool\SpoolStorageInterface $spool_storage
* The spool storage.
* @param \Drupal\simplenews\Mail\MailerInterface $mailer
* The mailer service.
*/
public function __construct(ConfigFactoryInterface $config_factory, SpoolStorageInterface $spool_storage, MailerInterface $mailer) {
parent::__construct();
$this->simplenewsConfig = $config_factory->get('simplenews.settings');
$this->spoolStorage = $spool_storage;
$this->mailer = $mailer;
}
/**
* Print the current simplenews mail spool count.
*
* @param array $options
* An associative array of options whose values come from cli, aliases,
* config, etc.
*
* @validate-module-enabled simplenews
*
* @command simplenews:spool-count
* @aliases sn-sc,simplenews-spool-count
*/
public function spoolCount(array $options) {
$count = $this->spoolStorage->countMails();
$no_description = $options['pipe'];
if ($no_description) {
$this->output()->writeln($count);
}
else {
$this->logger()->notice(dt('Current simplenews mail spool count: @count', ['@count' => $count]));
}
}
/**
* Send the defined amount of mail spool entries.
*
* @param int|bool $limit
* Number of mails to send. 0 sends all emails. If not specified, will be
* set to the value of the mail.throttle in the module settings config.
* @param array $options
* An associative array of options whose values come from cli, aliases,
* config, etc.
*
* @usage drush sn-ss
* Send the default amount of mails, as defined by the mail.throttle
* settings.
* @usage drush sn-ss 0
* Send all mails.
* @usage drush sn-ss 100
* Send 100 mails.
*
* @validate-module-enabled simplenews
*
* @command simplenews:spool-send
* @aliases sn-ss,simplenews-spool-send
*
* @throws \Exception
*/
public function spoolSend($limit = FALSE, array $options = ['pipe' => FALSE]) {
if (!simplenews_assert_uri()) {
throw new \Exception('Site URI not specified, use --uri.');
}
if ($limit === FALSE) {
$limit = $this->simplenewsConfig->get('mail.throttle');
}
elseif ($limit == 0) {
$limit = SpoolStorageInterface::UNLIMITED;
}
$start_time = microtime(TRUE);
$sent = $this->mailer->sendSpool($limit);
$this->spoolStorage->clear();
$this->mailer->updateSendStatus();
$durance = round(microtime(TRUE) - $start_time, 2);
// Report the number of sent mails.
if ($sent > 0) {
$remaining = $this->spoolStorage->countMails();
if ($options['pipe']) {
// For pipe, print the sent first and then the remaining count,
// separated by a space.
$this->output()->writeln($sent . " " . $remaining);
}
else {
$this->logger()->log(LogLevel::INFO, dt('Sent @count mails from the queue in @sec seconds.', ['@count' => $sent, '@sec' => $durance]));
$this->logger()->log(LogLevel::INFO, dt('Remaining simplenews mail spool count: @count', ['@count' => $remaining]));
}
}
}
}
<?php
namespace Drupal\simplenews\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Url;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Drupal\simplenews\Entity\Subscriber;
use Drupal\simplenews\Entity\Newsletter;
/**
* Returns responses for confirmation routes.
*/
class ConfirmationController extends ControllerBase {
/**
* Menu callback: confirm a combined confirmation request.
*
* This function is called by clicking the confirm link in the confirmation
* email. It handles both subscription addition and subscription removal.
*
* @param int $snid
* The subscriber id.
* @param int $timestamp
* The timestamp of the request.
* @param bool $hash
* The confirmation hash.
* @param bool $immediate
* Perform the action immediately if TRUE.
*
* @see simplenews_confirm_add_form()
* @see simplenews_confirm_removal_form()
*/
public function confirmCombined($snid, $timestamp, $hash, $immediate = FALSE) {
$config = \Drupal::config('simplenews.settings');
// Prevent search engines from indexing this page.
$html_head = [
[
'#tag' => 'meta',
'#attributes' => [
'name' => 'robots',
'content' => 'noindex',
],
],
'simplenews-noindex',
];
$subscriber = Subscriber::load($snid);
// Redirect and display message if no changes are available.
if ($subscriber && !$subscriber->getChanges()) {
$this->messenger()->addMessage($this->t('All changes to your subscriptions where already applied. No changes made.'));
return $this->redirect('<front>');
}
if ($subscriber && $hash == simplenews_generate_hash($subscriber->getMail(), 'combined' . serialize($subscriber->getChanges()), $timestamp)) {
// If the hash is valid but timestamp is too old, display form to request
// a new hash.
if ($timestamp < REQUEST_TIME - $config->get('hash_expiration')) {
$context = [
'simplenews_subscriber' => $subscriber,
];
$build = \Drupal::formBuilder()->getForm('\Drupal\simplenews\Form\RequestHashForm', 'subscribe_combined', $context);
$build['#attached']['html_head'][] = $html_head;
return $build;
}
// When not called with immediate parameter the user will be directed to
// the (un)subscribe confirmation page.
if (!$immediate) {
$build = \Drupal::formBuilder()->getForm('\Drupal\simplenews\Form\ConfirmMultiForm', $subscriber);
$build['#attached']['html_head'][] = $html_head;
return $build;
}
else {
/** @var \Drupal\simplenews\Subscription\SubscriptionManagerInterface $subscription_manager */
$subscription_manager = \Drupal::service('simplenews.subscription_manager');
// Redirect and display message if no changes are available.
foreach ($subscriber->getChanges() as $newsletter_id => $action) {
if ($action == 'subscribe') {
$subscription_manager->subscribe($subscriber->getMail(), $newsletter_id, FALSE, 'website');
}
elseif ($action == 'unsubscribe') {
$subscription_manager->unsubscribe($subscriber->getMail(), $newsletter_id, FALSE, 'website');
}
}
// Clear changes.
$subscriber->setChanges([]);
$subscriber->save();
$this->messenger()->addMessage($this->t('Subscription changes confirmed for %user.', ['%user' => $subscriber->getMail()]));
return $this->redirect('<front>');
}
}
throw new NotFoundHttpException();
}
/**
* Menu callback: confirm the user's (un)subscription request.
*
* This function is called by clicking the confirm link in the confirmation
* email or the unsubscribe link in the footer of the newsletter. It handles
* both subscription addition and subscription removal.
*
* Calling URLs are:
* newsletter/confirm/add
* newsletter/confirm/add/$HASH
* newsletter/confirm/remove
* newsletter/confirm/remove/$HASH
*
* @see simplenews_confirm_add_form()
* @see simplenews_confirm_removal_form()
*/
/**
* Menu callback: confirm the user's (un)subscription request.
*
* This function is called by clicking the confirm link in the confirmation
* email or the unsubscribe link in the footer of the newsletter. It handles
* both subscription addition and subscription removal.
*
* @param string $action
* Either add or remove.
* @param int $snid
* The subscriber id.
* @param int $newsletter_id
* The newsletter id.
* @param int $timestamp
* The timestamp of the request.
* @param string $hash
* The confirmation hash.
* @param bool $immediate
* Perform the action immediately if TRUE.
*
* @see simplenews_confirm_add_form()
* @see simplenews_confirm_removal_form()
*/
public function confirmSubscription($action, $snid, $newsletter_id, $timestamp, $hash, $immediate = FALSE) {
$config = \Drupal::config('simplenews.settings');
// Prevent search engines from indexing this page.
$html_head = [
[
'#tag' => 'meta',
'#attributes' => [
'name' => 'robots',
'content' => 'noindex',
],
],
'simplenews-noindex',
];
$subscriber = Subscriber::load($snid);
if ($subscriber && $hash == simplenews_generate_hash($subscriber->getMail(), $action, $timestamp)) {
$newsletter = Newsletter::load($newsletter_id);
// If the hash is valid but timestamp is too old, display form to request
// a new hash.
if ($timestamp < REQUEST_TIME - $config->get('hash_expiration')) {
$context = [
'simplenews_subscriber' => $subscriber,
'newsletter' => $newsletter,
];
$token = $action == 'add' ? 'subscribe' : 'unsubscribe';
$build = \Drupal::formBuilder()->getForm('\Drupal\simplenews\Form\RequestHashForm', $token, $context);
$build['#attached']['html_head'][] = $html_head;
return $build;
}
// When called with additional arguments the user will be directed to the
// (un)subscribe confirmation page. The additional arguments will be
// passed on to the confirmation page.
if (!$immediate) {
if ($action == 'remove') {
$build = \Drupal::formBuilder()->getForm('\Drupal\simplenews\Form\ConfirmRemovalForm', $subscriber->getMail(), $newsletter);
$build['#attached']['html_head'][] = $html_head;
return $build;
}
elseif ($action == 'add') {
$build = \Drupal::formBuilder()->getForm('\Drupal\simplenews\Form\ConfirmAddForm', $subscriber->getMail(), $newsletter);
$build['#attached']['html_head'][] = $html_head;
return $build;
}
}
else {
/** @var \Drupal\simplenews\Subscription\SubscriptionManagerInterface $subscription_manager */
$subscription_manager = \Drupal::service('simplenews.subscription_manager');
if ($action == 'remove') {
$subscription_manager->unsubscribe($subscriber->getMail(), $newsletter_id, FALSE, 'website');
if ($path = $config->get('subscription.confirm_unsubscribe_page')) {
return $this->redirect(Url::fromUri("internal:$path")->getRouteName());
}
$this->messenger()->addMessage($this->t('%user was unsubscribed from the %newsletter mailing list.', ['%user' => $subscriber->getMail(), '%newsletter' => $newsletter->name]));
return $this->redirect('<front>');
}
elseif ($action == 'add') {
$subscription_manager->subscribe($subscriber->getMail(), $newsletter_id, FALSE, 'website');
if ($path = $config->get('subscription.confirm_subscribe_page')) {
return $this->redirect(Url::fromUri("internal:$path")->getRouteName());
}
$this->messenger()->addMessage($this->t('%user was added to the %newsletter mailing list.', ['%user' => $subscriber->getMail(), '%newsletter' => $newsletter->name]));
return $this->redirect('<front>');
}
}
}
throw new NotFoundHttpException();
}
}
<?php
namespace Drupal\simplenews\Entity;
use Drupal\block\Entity\Block;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\simplenews\NewsletterInterface;
/**
* Defines the simplenews newsletter entity.
*
* @ConfigEntityType(
* id = "simplenews_newsletter",
* label = @Translation("Simplenews newsletter"),
* handlers = {
* "list_builder" = "Drupal\simplenews\NewsletterListBuilder",
* "form" = {
* "add" = "Drupal\simplenews\Form\NewsletterForm",
* "edit" = "Drupal\simplenews\Form\NewsletterForm",
* "delete" = "Drupal\simplenews\Form\NewsletterDeleteForm"
* }
* },
* config_prefix = "newsletter",
* admin_permission = "administer newsletters",
* entity_keys = {
* "id" = "id",
* "label" = "name"
* },
* config_export = {
* "name",
* "id",
* "description",
* "format",
* "priority",
* "receipt",
* "from_name",
* "subject",
* "from_address",
* "hyperlinks",
* "allowed_handlers",
* "new_account",
* "access",
* "weight",
* },
* links = {
* "delete-form" = "/admin/config/services/simplenews/manage/{simplenews_newsletter}/delete",
* "edit-form" = "/admin/config/services/simplenews/manage/{simplenews_newsletter}"
* }
* )
*/
class Newsletter extends ConfigEntityBase implements NewsletterInterface {
/**
* The primary key.
*
* @var string
*/
public $id;
/**
* Name of the newsletter.
*
* @var string
*/
public $name = '';
/**
* Description of the newsletter.
*
* @var string
*/
public $description = '';
/**
* HTML or plaintext newsletter indicator.
*
* @var string
*/
public $format;
/**
* Priority indicator.
*
* @var int
*/
public $priority;
/**
* TRUE if a read receipt should be requested.
*
* @var bool
*/
public $receipt;
/**
* Name of the email author.
*
* @var string
*/
public $from_name;
/**
* Subject of newsletter email. May contain tokens.
*
* @var string
*/
public $subject = '[[simplenews-newsletter:name]] [node:title]';
/**
* Email author address.
*
* @var string
*/
public $from_address;
/**
* Indicates if hyperlinks should be kept inline or extracted.
*
* @var bool
*/
public $hyperlinks = TRUE;
/**
* Allowed recipient handlers.
*
* If none are selected, then all of them will be available.
*
* @var array
*/
public $allowed_handlers = [];
/**
* Indicates how to integrate with the register form.
*
* @var string
*/
public $new_account = 'none';
/**
* Controls access to subscribe and unsubscribe.
*
* @var string
*/
public $access = SIMPLENEWS_ACCESS_DEFAULT;
/**
* Weight of this newsletter (used for sorting).
*
* @var int
*/
public $weight = 0;
/**
* {@inheritdoc}
*/
public static function preCreate(EntityStorageInterface $storage, array &$values) {
$config = \Drupal::config('simplenews.settings');
$values += [
'format' => $config->get('newsletter.format'),
'priority' => $config->get('newsletter.priority'),
'receipt' => $config->get('newsletter.receipt'),
'from_name' => $config->get('newsletter.from_name'),
'from_address' => $config->get('newsletter.from_address'),
];
parent::preCreate($storage, $values);
}
/**
* {@inheritdoc}
*/
public static function postDelete(EntityStorageInterface $storage, array $entities) {
parent::postDelete($storage, $entities);
/** @var \Drupal\simplenews\Subscription\SubscriptionStorageInterface $subscription_storage */
$subscription_storage = \Drupal::entityTypeManager()
->getStorage('simplenews_subscriber');
foreach ($entities as $newsletter) {
$subscription_storage->deleteSubscriptions(['subscriptions_target_id' => $newsletter->id()]);
\Drupal::messenger()->addMessage(t('All subscriptions to newsletter %newsletter have been deleted.', ['%newsletter' => $newsletter->label()]));
}
if (\Drupal::moduleHandler()->moduleExists('block')) {
// Make sure there are no active blocks for these newsletters.
$ids = \Drupal::entityQuery('block')
->condition('plugin', 'simplenews_subscription_block')
->condition('settings.newsletters.*', array_keys($entities), 'IN')
->execute();
if ($ids) {
$blocks = Block::loadMultiple($ids);
foreach ($blocks as $block) {
$settings = $block->get('settings');
foreach ($entities as $newsletter) {
if (in_array($newsletter->id(), $settings['newsletters'])) {
unset($settings['newsletters'][array_search($newsletter->id(), $settings['newsletters'])]);
}
}
// If there are no enabled newsletters left, delete the block.
if (empty($settings['newsletters'])) {
$block->delete();
}
else {
// otherwise, update the settings and save.
$block->set('settings', $settings);
$block->save();
}
}
}
}
}
/**
* {@inheritdoc}
*/
public function isAccessible() {
return $this->access == SIMPLENEWS_ACCESS_DEFAULT;
}
}
<?php
namespace Drupal\simplenews\EventSubscriber;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\migrate\Event\MigrateEvents;
use Drupal\migrate\Event\MigratePostRowSaveEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Create a simplenews field on relevant content types.
*
* Since simplenews configuration on a node is stored as a field, it has to
* be added explicitly during a migration. This listener checks if the node
* type is a simplenews content type and adds the field.
*/
class MigrationSubscriber implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* The entity display repository.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected $entityDisplayRepository;
/**
* Constructs a new migration subscriber.
*
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager
* The entity field manager service.
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
* The entity display repository.
*/
public function __construct(EntityFieldManagerInterface $entityFieldManager, EntityDisplayRepositoryInterface $entity_display_repository) {
$this->entityFieldManager = $entityFieldManager;
$this->entityDisplayRepository = $entity_display_repository;
}
/**
* Create simplenews field if applicable.
*
* @param \Drupal\migrate\Event\MigratePostRowSaveEvent $event
* The event object.
*/
public function onMigrationPostRowSave(MigratePostRowSaveEvent $event) {
if (!$event->getRow()->getSourceProperty('simplenews_content_type')) {
return;
}
$node_type = reset($event->getDestinationIdValues());
$fields = $this->entityFieldManager->getFieldDefinitions('node', $node_type);
if (isset($fields['simplenews_issue'])) {
return;
}
// If checked and the field does not exist yet, create it.
$field_storage = FieldStorageConfig::loadByName('node', 'simplenews_issue');
$field = FieldConfig::create([
'field_storage' => $field_storage,
'label' => $this->t('Issue'),
'bundle' => $node_type,
'translatable' => TRUE,
]);
$field->save();
// Set the default widget.
$this->entityDisplayRepository->getFormDisplay('node', $node_type)
->setComponent($field->getName())
->save();
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$return = [];
if (class_exists('\Drupal\migrate\Event\MigrateEvents')) {
$return[MigrateEvents::POST_ROW_SAVE][] = 'onMigrationPostRowSave';
}
return $return;
}
}
<?php
namespace Drupal\simplenews\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\simplenews\NewsletterInterface;
/**
* Implements a add confirmation form for simplenews subscriptions.
*/
class ConfirmAddForm extends ConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Confirm subscription');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Subscribe');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('You can always unsubscribe later.');
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'simplenews_confirm_add';
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('simplenews.newsletter_subscriptions');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $mail = '', NewsletterInterface $newsletter = NULL) {
$form = parent::buildForm($form, $form_state);
$form['question'] = [
'#markup' => '<p>' . $this->t('Are you sure you want to add %user to the %newsletter mailing list?', ['%user' => simplenews_mask_mail($mail), '%newsletter' => $newsletter->name]) . "<p>\n",
];
$form['mail'] = [
'#type' => 'value',
'#value' => $mail,
];
$form['newsletter'] = [
'#type' => 'value',
'#value' => $newsletter,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
\Drupal::service('simplenews.subscription_manager')->subscribe($form_state->getValue('mail'), $form_state->getValue('newsletter')->id(), FALSE, 'website');
$config = \Drupal::config('simplenews.settings');
if ($path = $config->get('subscription.confirm_subscribe_page')) {
$form_state->setRedirectUrl(Url::fromUri("internal:$path"));
}
else {
$this->messenger()->addMessage($this->t('%user was added to the %newsletter mailing list.', ['%user' => $form_state->getValue('mail'), '%newsletter' => $form_state->getValue('newsletter')->name]));
$form_state->setRedirect('<front>');
}
}
}
<?php
namespace Drupal\simplenews\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\simplenews\SubscriberInterface;
/**
* Implements a multi confirmation form for simplenews subscriptions.
*/
class ConfirmMultiForm extends ConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Confirm subscription');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('You can always change your subscriptions later.');
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'simplenews_confirm_multi';
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('simplenews.newsletter_subscriptions');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, SubscriberInterface $subscriber = NULL) {
$form = parent::buildForm($form, $form_state);
$form['question'] = [
'#markup' => '<p>' . $this->t('Are you sure you want to confirm the following subscription changes for %user?', ['%user' => simplenews_mask_mail($subscriber->getMail())]) . "<p>\n",
];
/** @var \Drupal\simplenews\Subscription\SubscriptionManagerInterface $subscription_manager */
$subscription_manager = \Drupal::service('simplenews.subscription_manager');
$form['changes'] = [
'#theme' => 'item_list',
'#items' => $subscription_manager->getChangesList($subscriber),
];
$form['subscriber'] = [
'#type' => 'value',
'#value' => $subscriber,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$subscriber = $form_state->getValue('subscriber');
foreach ($subscriber->getChanges() as $newsletter_id => $action) {
if ($action == 'subscribe') {
if (!$subscriber->isSubscribed($newsletter_id)) {
// Subscribe the user if not already subscribed.
$subscriber->subscribe($newsletter_id);
}
}
elseif ($action == 'unsubscribe') {
if ($subscriber->isSubscribed($newsletter_id)) {
// Subscribe the user if not already subscribed.
$subscriber->unsubscribe($newsletter_id);
}
}
}
// Clear changes.
$subscriber->setChanges([]);
$subscriber->save();
$this->messenger()->addMessage($this->t('Subscription changes confirmed for %user.', ['%user' => $subscriber->getMail()]));
$form_state->setRedirect('<front>');
}
}
<?php
namespace Drupal\simplenews\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\simplenews\NewsletterInterface;
/**
* Implements a removal confirmation form for simplenews subscriptions.
*/
class ConfirmRemovalForm extends ConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Confirm remove subscription');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Unsubscribe');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('This action will unsubscribe you from the newsletter mailing list.');
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'simplenews_confirm_removal';
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('simplenews.newsletter_subscriptions');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $mail = '', NewsletterInterface $newsletter = NULL) {
$form = parent::buildForm($form, $form_state);
$form['question'] = [
'#markup' => '<p>' . $this->t('Are you sure you want to remove %user from the %newsletter mailing list?', ['%user' => simplenews_mask_mail($mail), '%newsletter' => $newsletter->name]) . "<p>\n",
];
$form['mail'] = [
'#type' => 'value',
'#value' => $mail,
];
$form['newsletter'] = [
'#type' => 'value',
'#value' => $newsletter,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
\Drupal::service('simplenews.subscription_manager')->unsubscribe($form_state->getValue('mail'), $form_state->getValue('newsletter')->id(), FALSE, 'website');
$config = \Drupal::config('simplenews.settings');
if ($path = $config->get('subscription.confirm_unsubscribe_page')) {
$form_state->setRedirectUrl(Url::fromUri("internal:$path"));
}
else {
$this->messenger()->addMessage($this->t('%user was unsubscribed from the %newsletter mailing list.', ['%user' => $form_state->getValue('mail'), '%newsletter' => $form_state->getValue('newsletter')->name]));
$form_state->setRedirect('<front>');
}
}
}
<?php
namespace Drupal\simplenews\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simplenews\Spool\SpoolStorageInterface;
/**
* Configure simplenews newsletter settings.
*/
class MailSettingsForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'simplenews_admin_settings_mail';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['simplenews.settings'];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('simplenews.settings');
$form['simplenews_mail_backend']['simplenews_use_cron'] = [
'#type' => 'checkbox',
'#title' => $this->t('Use cron to send newsletters'),
'#default_value' => $config->get('mail.use_cron'),
'#description' => $this->t('When checked cron will be used to send newsletters (recommended). Test newsletters and confirmation emails will be sent immediately. Leave unchecked for testing purposes.'),
];
$form['simplenews_mail_backend']['simplenews_textalt'] = [
'#type' => 'checkbox',
'#title' => $this->t('Generate plain-text alternative'),
'#default_value' => $config->get('mail.textalt'),
'#description' => $this->t('Generate plain-text alternative for HTML mails (less recommended). If you are using the recommended Swift Mailer module then disable this option and allow that module to generate them. If you enable this option then you need to configure both "Email: HTML" and "Email: Plain" view modes.'),
];
$throttle_val = [
1, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000,
];
$throttle = array_combine($throttle_val, $throttle_val);
$throttle[SpoolStorageInterface::UNLIMITED] = $this->t('Unlimited');
if (function_exists('getrusage')) {
$description_extra = '<br />' . $this->t('Cron execution must not exceed the PHP maximum execution time of %max seconds. You can find the time taken to send emails in the <a href="/admin/reports/dblog">Recent log entries</a>.', ['%max' => ini_get('max_execution_time')]);
}
else {
$description_extra = '<br />' . $this->t('Cron execution must not exceed the PHP maximum execution time of %max seconds.', ['%max' => ini_get('max_execution_time')]);
}
$form['simplenews_mail_backend']['simplenews_throttle'] = [
'#type' => 'select',
'#title' => $this->t('Cron throttle'),
'#options' => $throttle,
'#default_value' => $config->get('mail.throttle'),
'#description' => $this->t('Sets the number of newsletters processed per cron run. Failures and skipped entries count towards the total.') . $description_extra,
];
$form['simplenews_mail_backend']['simplenews_spool_expire'] = [
'#type' => 'select',
'#title' => $this->t('Mail spool expiration'),
'#options' => [
0 => $this->t('Immediate'),
1 => \Drupal::translation()->formatPlural(1, '1 day', '@count days'),
7 => \Drupal::translation()->formatPlural(1, '1 week', '@count weeks'),
14 => \Drupal::translation()->formatPlural(2, '1 week', '@count weeks'),
],
'#default_value' => $config->get('mail.spool_expire'),
'#description' => $this->t('Controls the duration that messages are retained in the spool after processing. Keeping messages in the spool can be useful for statistics or analysing errors.'),
];
$form['simplenews_mail_backend']['simplenews_debug'] = [
'#type' => 'checkbox',
'#title' => $this->t('Log emails'),
'#default_value' => $config->get('mail.debug'),
'#description' => $this->t('When checked all outgoing simplenews emails are logged in the system log. A logged success does not guarantee delivery. The default PHP mail() function returns success without waiting to check if the mail can be delivered.'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('simplenews.settings')
->set('mail.use_cron', $form_state->getValue('simplenews_use_cron'))
->set('mail.textalt', $form_state->getValue('simplenews_textalt'))
->set('mail.source_cache', $form_state->getValue('simplenews_source_cache'))
->set('mail.throttle', $form_state->getValue('simplenews_throttle'))
->set('mail.spool_expire', $form_state->getValue('simplenews_spool_expire'))
->set('mail.debug', $form_state->getValue('simplenews_debug'))
->save();
parent::submitForm($form, $form_state);
}
}
<?php
namespace Drupal\simplenews\Form;
use Drupal\Core\Entity\EntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
/**
* Builds the form to delete a contact category.
*/
class NewsletterDeleteForm extends EntityConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]);
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('simplenews.newsletter_list');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Delete');
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->entity->delete();
$this->messenger()->addMessage($this->t('Newsletter %label has been deleted.', ['%label' => $this->entity->label()]));
\Drupal::logger('simplenews')->notice('Newsletter %label has been deleted.', ['%label' => $this->entity->label()]);
$form_state->setRedirect('simplenews.newsletter_list');
}
}
<?php
namespace Drupal\simplenews\Form;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Base form for category edit forms.
*/
class NewsletterForm extends EntityForm {
/**
* Overrides Drupal\Core\Entity\EntityForm::form().
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$newsletter = $this->entity;
$form['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Name'),
'#maxlength' => 255,
'#default_value' => $newsletter->label(),
'#description' => $this->t("The newsletter name."),
'#required' => TRUE,
];
$form['id'] = [
'#type' => 'machine_name',
'#default_value' => $newsletter->id(),
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
'#machine_name' => [
'exists' => ['Drupal\simplenews\Entity\Newsletter', 'load'],
'source' => ['name'],
],
'#disabled' => !$newsletter->isNew(),
];
$form['description'] = [
'#type' => 'textarea',
'#title' => $this->t('Description'),
'#default_value' => $newsletter->description,
'#description' => $this->t("A description of the newsletter."),
];
$links = [':mime_mail_url' => 'http://drupal.org/project/mimemail', ':html_url' => 'http://drupal.org/project/htmlmail'];
$description = $this->t('Newsletter format. Install <a href=":mime_mail_url">Mime Mail</a> module or <a href=":html_url">HTML Mail</a> module to send newsletters in HTML format.', $links);
$form['weight'] = [
'#type' => 'hidden',
'#value' => $newsletter->weight,
];
$form['subscription'] = [
'#type' => 'fieldset',
'#title' => $this->t('Subscription settings'),
'#collapsible' => FALSE,
];
// Allowed recipient handlers.
$options = \Drupal::service('plugin.manager.simplenews_recipient_handler')->getOptions();
$form['subscription']['allowed_handlers'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Allowed recipient handlers'),
'#options' => $options,
'#default_value' => $newsletter->allowed_handlers,
'#description' => $this->t('Restrict which recipient handlers are allowed when using this newsletter. If none are selected, then all of them will be available.'),
'#access' => count($options) > 1,
];
// Subscribe at account registration time.
$options = simplenews_new_account_options();
$form['subscription']['new_account'] = [
'#type' => 'select',
'#title' => $this->t('Subscribe new account'),
'#options' => $options,
'#default_value' => $newsletter->new_account,
'#description' => $this->t('None: This newsletter is not listed on the user registration page.<br />Default on: This newsletter is listed on the user registion page and is selected by default.<br />Default off: This newsletter is listed on the user registion page and is not selected by default.<br />Silent: A new user is automatically subscribed to this newsletter. The newsletter is not listed on the user registration page.'),
];
// Type of (un)subsribe confirmation.
$options = simplenews_access_options();
$form['subscription']['access'] = [
'#type' => 'select',
'#title' => $this->t('Access'),
'#options' => $options,
'#default_value' => $newsletter->access,
'#description' => $this->t("Default: Any user with 'Subscribe to newsletters' permission can subscribe and unsubscribe.<br />Hidden: Subscription is mandatory or controlled programmatically."),
];
$form['email'] = [
'#type' => 'fieldset',
'#title' => $this->t('Email settings'),
'#collapsible' => FALSE,
];
// Hide format selection if there is nothing to choose.
// The default format is plain text.
$format_options = simplenews_format_options();
if (count($format_options) > 1) {
$form['email']['format'] = [
'#type' => 'radios',
'#title' => $this->t('Email format'),
'#default_value' => $newsletter->format,
'#options' => $format_options,
];
}
else {
$form['email']['format'] = [
'#type' => 'hidden',
'#value' => key($format_options),
];
$form['email']['format_text'] = [
'#markup' => $this->t('Newsletter emails will be sent in %format format.', ['%format' => $newsletter->format]),
];
}
// Type of hyperlinks.
$form['email']['hyperlinks'] = [
'#type' => 'radios',
'#title' => $this->t('Hyperlink conversion'),
'#description' => $this->t('Determine how the conversion to text is performed.'),
'#options' => [$this->t('Append hyperlinks as a numbered reference list'), $this->t('Display hyperlinks inline with the text')],
'#default_value' => $newsletter->hyperlinks,
'#states' => [
'visible' => [
':input[name="format"]' => [
'value' => 'plain',
],
],
],
];
$form['email']['priority'] = [
'#type' => 'select',
'#title' => $this->t('Email priority'),
'#default_value' => $newsletter->priority,
'#options' => simplenews_get_priority(),
];
$form['email']['receipt'] = [
'#type' => 'checkbox',
'#title' => $this->t('Request receipt'),
'#return_value' => 1,
'#default_value' => $newsletter->receipt,
];
// Email sender name.
$form['simplenews_sender_information'] = [
'#type' => 'fieldset',
'#title' => $this->t('Sender information'),
'#collapsible' => FALSE,
];
$form['simplenews_sender_information']['from_name'] = [
'#type' => 'textfield',
'#title' => $this->t('From name'),
'#size' => 60,
'#maxlength' => 128,
'#default_value' => $newsletter->from_name,
];
// Email subject.
$form['simplenews_subject'] = [
'#type' => 'fieldset',
'#title' => $this->t('Newsletter subject'),
'#collapsible' => FALSE,
];
$form['simplenews_subject']['subject'] = [
'#type' => 'textfield',
'#title' => $this->t('Email subject'),
'#size' => 60,
'#maxlength' => 128,
'#required' => TRUE,
'#default_value' => $newsletter->subject,
];
if (\Drupal::moduleHandler()->moduleExists('token')) {
$form['simplenews_subject']['token_browser'] = [
'#theme' => 'token_tree_link',
'#token_types' => [
'simplenews-newsletter', 'node', 'simplenews-subscriber',
],
];
}
// Email from address.
$form['simplenews_sender_information']['from_address'] = [
'#type' => 'email',
'#title' => $this->t('From email address'),
'#size' => 60,
'#maxlength' => 128,
'#required' => TRUE,
'#default_value' => $newsletter->from_address,
];
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Save'),
'#weight' => 50,
];
if ($newsletter->id) {
$form['actions']['delete'] = [
'#type' => 'submit',
'#value' => $this->t('Delete'),
'#weight' => 55,
];
}
return $form;
}
/**
* Overrides Drupal\Core\Entity\EntityForm::save().
*/
public function save(array $form, FormStateInterface $form_state) {
$newsletter = $this->entity;
$status = $newsletter->save();
$edit_link = \Drupal::linkGenerator()->generate($this->t('Edit'), $this->entity->toUrl());
if ($status == SAVED_UPDATED) {
$this->messenger()->addMessage($this->t('Newsletter %label has been updated.', ['%label' => $newsletter->label()]));
\Drupal::logger('simplenews')->notice('Newsletter %label has been updated.', ['%label' => $newsletter->label(), 'link' => $edit_link]);
}
else {
$this->messenger()->addMessage($this->t('Newsletter %label has been added.', ['%label' => $newsletter->label()]));
\Drupal::logger('simplenews')->notice('Newsletter %label has been added.', ['%label' => $newsletter->label(), 'link' => $edit_link]);
}
$form_state->setRedirect('simplenews.newsletter_list');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment