-
Notifications
You must be signed in to change notification settings - Fork 83
Implement wagtail-newsletter #519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
I've added a management command to import a newsletter edition: ./manage.py import_newsletter https://mailchi.mp/wagtail/twiw-11034221 "Issue #180"It will skip over the date and the footer, detect headings, copy images, and preserve links in the text. It doesn't copy the "Packages" section using the right block type ( |
|
FYI Alex. I got all the packages installed and such to test your branch but I'm running into a migration error that reads:
Baptiste suggested that we split one of the migration files in two. Apparently Postgres doesn't like it when you try to combine certain actions together. I'm going to attempt that and see if it fixes the issue. If I have no luck, I may need you to take another look at this or help me through the fiddly migration parts. |
|
I couldn't replicate the migration error, but I've encountered such errors in the past, and I think it's best to avoid them. I've split the migration into two steps. |
| migrations.RemoveField( | ||
| model_name="newsletterpage", | ||
| name="body", | ||
| ), | ||
| migrations.RemoveField( | ||
| model_name="newsletterpage", | ||
| name="intro", | ||
| ), | ||
| migrations.RenameField( | ||
| model_name="newsletterpage", | ||
| old_name="content", | ||
| new_name="body", | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend splitting the RemoveField operations to another migration. The problem tends to happen if you have both a data migration operation (in this case RunPython(convert_body_to_streamfield)) and a schema migration operation in a single migration. Migrations are run in a single transaction (if the backend supports DDL transactions), and the database may not allow data manipulation in a DDL transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. I've also noticed that images were not getting preserved in the data migration so I've fixed that too.
|
@mgax I ran into issues with the migration script not parsing the images correctly. I've pushed a fixup commit for that, please review. |
Stormheg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgax couple minors comments.
Impressed by the migration of the old issues (Issues <= 138). Though this is not how they originally looked, though I don't think it is super important to keep their original look. They look clean now.
The detail view of a newsletter will load the email-formatted HTML from a variable into the shadow DOM of a
, so that its styling doesn't break the header and footer. I'm not sure how well this plays with search engines.
Have you considered loading the email HTML in an iframe? That should accomplish mostly the same thing. Iframes have been around for so long it is more likely they behave nicely in the context of SEO - if that is even important.
wagtailio/newsletter/models.py
Outdated
|
|
||
| @register_setting | ||
| class NewsletterSettings(BaseGenericSetting): | ||
| footer = StreamField(NewsletterContentBlock(), blank=True, use_json_field=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgax this and the StreamField below don't require setting use_json_field anymore, see https://docs.wagtail.org/en/stable/releases/6.0.html#streamfield-no-longer-requires-use-json-field-true
| footer = StreamField(NewsletterContentBlock(), blank=True, use_json_field=True) | |
| footer = StreamField(NewsletterContentBlock(), blank=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in d00d9b0.
wagtailio/newsletter/models.py
Outdated
| class NewsletterPage(NewsletterPageMixin, Page): | ||
| date = models.DateField() | ||
| preview = models.TextField(blank=True) | ||
| body = StreamField(NewsletterContentBlock(), blank=True, use_json_field=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| body = StreamField(NewsletterContentBlock(), blank=True, use_json_field=True) | |
| body = StreamField(NewsletterContentBlock(), blank=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in d00d9b0.
wagtailio/newsletter/models.py
Outdated
| search_fields = Page.search_fields + [ | ||
| index.SearchField("intro"), | ||
| index.SearchField("body"), | ||
| index.SearchField("body"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accidental double?
| index.SearchField("body"), |
| <p> | ||
| Want to change how you receive these emails? You can | ||
| <a href="*|UPDATE_PROFILE|*">update your preferences</a> or | ||
| <a href="*|UNSUB|*">unsubscribe from this list</a>. | ||
| </p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in bec1ad0.
| <mj-text align="center" css-class="rich-text"> | ||
| <a href="{{ page.full_url }}">View this email online</a> | ||
| </mj-text> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as below - shouldn't this be hidden on the web version of the page?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in bec1ad0.
| <script> | ||
| (function() { | ||
| const container = document.getElementById("newsletter-container"); | ||
| const shadow = container.attachShadow({mode: "open"}); | ||
| const wrapper = document.createElement("div"); | ||
| wrapper.innerHTML = JSON.parse(document.getElementById("email-html-data").textContent); | ||
| shadow.appendChild(wrapper); | ||
| })(); | ||
| </script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: maybe there is an alternative for the shadow dom?
Issue: otherwise this should be converted to a dedicated JS script that is loaded on this page and creates the shadow DOM.
Adding inline JS is not acceptable as we're trying to add a Content Security Policy (see #468) in the future, which does not allow for inline JS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in c65e242. It turns out you can inline the shadow dom content.
Getting the iframe height is notoriously difficult. Also, I suspect the search engines might index the content at the iframe's src url, which is not great. But it turns out that you can inline the content for the shadow dom, and it seems search engine will index it: https://dev.to/stuffbreaker/seo-and-web-components-2023-edition-3l6i |
|
I also made a Also @vossisboss, did we skip issue 163? It doesn't seem to be in my personal email archive either. |
The importing is fixed now, I've checked all of the back issues by opening them in the browser and having a quick glance. This PR is ready for another review. And I almost forgot: thank you @Stormheg for the thorough review and the fix to the data migration code 🙌 |
|
@mgax We may have skipped an issue. I wouldn't be surprised. It will just be a part of Wagtail lore now. I am testing your code right now. I pushed the Wagtail 7.0 upgrade today, so would you mind rebasing this to the latest version? I don't have a lot more time left in my day to test this so I might pick this up again in the morning and send you my notes. I can confirm that the database issue was solved though and I got the development server to start. |
@vossisboss I did a merge with |
|
I had some time today and I've polished this PR. I think it's just about ready for prime time. @vossisboss I've implemented the short list of things that you've flagged:
Also, I've bumped wagtail-newsletter to the newly released v0.2.3, and updated the list of existing newsletters to import. @vossisboss please check that I've got the numbering right! |

Fixes #481. This PR supersedes #492.
I was able to replicate a recent newsletter edition with very small spacing differences. I'm pretty happy with the editing experience and have somewhat tested this using Litmus. The main issue with testing is that images are served locally, so Litmus can't load them; we'd need to either deploy this to staging, or use a tunnelling tool like ngrok.
Things that I'm not so happy about:
There's no code to migrate the archive from Mailchimp just yet. I'm hoping that an AI might make writing that code not too painful.Import works.The detail view of a newsletter will load the email-formatted HTML from a variable into the shadow DOM of aThe content is now rendered using the Declarative Shadow DOM syntax.<div>, so that its styling doesn't break the header and footer. I'm not sure how well this plays with search engines.TheFixed.import_newsletter_archivecommand doesn't work for TWiW issues 138 through 172.