I'm in the process of converting an existing Django project to Wagtail. One issue I'm having is email notifications. In the Django project, I have the ability for people to subscribe to a blog, and whenever a new post is published, the author can manually send out a notification to all subscribers in the admin. However, I'm not sure how to accomplish this in Wagtail.
I've read the docs about the page_published signal (https://docs.wagtail.io/en/stable/reference/signals.html#page-published), however, I'm not sure how I could integrate my current code into it. In addition, I would prefer for the author to manually send out the notification, as the author doesn't want to email their subscribers every time a blog post is edited and subsequently published.
For reference, the current code I have for the Django app is as follows (it only works if the blog app is in normal Django; because the blog models are now in the Wagtail app, the current code no longer works).
models.py
class Post(models.Model):
"""Fields removed here for brevity."""
...
def send(self, request):
subscribers = Subscriber.objects.filter(confirmed=True)
sg = SendGridAPIClient(settings.SENDGRID_API_KEY)
for sub in subscribers:
message = Mail(
from_email=settings.FROM_EMAIL,
to_emails=sub.email,
subject="New blog post!",
html_content=( #Abbreviated content here for brevity
'Click the following link to read the new post:' \
'<a href="{}/{}/">{}</a>'\
'Or, you can copy and paste the following url into your browser:' \
'{}/{}'\
'<hr>If you no longer wish to receive our blog updates, you can ' \
'<a href="{}/?email={}&conf_num={}">unsubscribe</a>.').format(
request.build_absolute_uri('/post'),
self.slug,
self.title,
request.build_absolute_uri('/post'),
self.slug,
request.build_absolute_uri('/delete'),
sub.email,
sub.conf_num
)
)
sg.send(message)
admin.py
def send_notification(modeladmin, request, queryset):
for post in queryset:
post.send(request)
send_notification.short_description = "Send selected Post(s) to all subscribers"
@admin.register(Post)
class PostAdmin(SummernoteModelAdmin):
...
actions = [send_notification]
Any suggestions or feedback would be greatly appreciated! Thanks in advance!
EDIT 1
I got a suggestion from the Wagtail Slack to use the register_page_action_menu_item hook (https://docs.wagtail.io/en/stable/reference/hooks.html?highlight=hooks#register-page-action-menu-item). I successfully implemented the action menu item on Wagtail's page editor, however I cannot get my email method to execute (likely due to my not knowing how to properly use the hook). Below is the code from my wagtail_hooks.py file.
from wagtail.admin.action_menu import ActionMenuItem
from wagtail.core import hooks
from .models import Subscriber
from django.conf import settings
from django.core.mail import send_mail
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import (Mail, Attachment, FileContent, FileName, FileType, Disposition)
class NotificationMenuItem(ActionMenuItem):
name = 'email-notification'
label = "Notify Subscribers of New Post"
def send(self, request):
"""Used the same def send() method here from my models.py above"""
@hooks.register('register_page_action_menu_item')
def register_notification_menu_item():
return NotificationMenuItem(order=100)
If anyone has advice on how to fix it so it executes, please let me know!
EDIT 2
More problems! (Though I think I'm getting closer.)
Modifying the wagtail_hooks.py to the following, I am able to send an email, but it happens on pageload. So every time I load a blog post in the editor, it sends an email. Clicking the action menu item I created triggers a page reload, which then sends another email (so I don't think my action menu item is actually working when clicked).
Another problem: Because I moved the send() method into the NotificationMenuItem class, I am unable to dynamically generate a blog post's slug and title in the urls of the email.
wagtail_hooks.py
class NotificationMenuItem(ActionMenuItem):
name = 'email-notification'
label = "Notify Subscribers of New Post"
def send(self, request):
"""Used the same def send() method here from my models.py above"""
def get_url(self, request, context):
self.send(request)
EDIT 3
I managed to get the notification system to work in the regular Django admin despite the models being Wagtail models. While this moves the current website's functionality over to the new wagtail site, I still have been unable to solve the most recent issues raised under Edit 2.
Here's the new code in the admin:
def send_notification(modeladmin, request, queryset):
for post in queryset:
post.send(request)
send_notification.short_description = "Send selected Post(s) to all subscribers"
class BlogPageAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'body')
search_fields = ['title', 'body']
actions = [send_notification]
admin.site.register(BlogPage, BlogPageAdmin)