Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

Adding a subscription form to the web views of Mailcoach

Original – by Freek Van der Herten – 4 minute read

After sending a new edition of my newsletter, I usually tweet out a webview URL together with a URL where people can subscribe to the newsletter. A webview is a hard to guess URL that people who didn't subscribe can visit to read the content of the newsletter.

Until last week, the webview URL just displayed the content of the sent campaign. Recently, I added a subscription form to that webpage, so people don't need to go to a separate page to subscribe. Here's how that looks like:

screenshot

In this blog post, I'd like to share how that subscription form was added.

Customizing the webview

It probably comes as no surprise that I use our homegrown Mailcoach package to sent out my newsletter. Whenever a campaign (that's Mailcoach speak for newsletter) is sent, Mailcoach makes the campaign available as webview.

You can get to the URL of the webview of a campaign:

$campaign->webViewUrl();

Up until last week, I just used the webViewUrl in the Blade view that displays all past campaigns

@foreach($pastCampaigns as $campaign)
    <div>
        <a href="{{ $campaign->webViewUrl() }}">{{ $campaign->subject }}</a>
        <div class="text-gray-700 text-xs">sent on {{ $campaign->sent_at->format('jS F Y') }}</div>
    </div>
@endforeach

The first thing I did was create a route newsletter.show of my own to take control of which view is rendered when people see an archived newsletter.

@foreach($pastCampaigns as $campaign)
    <div>
        <a href="{{ route('newsletter.show', $campaign->id) }}">{{ $campaign->subject }}</a>
        <div class="text-gray-700 text-xs">sent on {{ $campaign->sent_at->format('jS F Y') }}</div>
    </div>
@endforeach

The controller that gets called to serve the newsletter.show route, returns the newsletter.blade.php view.

From using an iframe...

This was my first naive approach to display a form above the webview. The HTML page just started with a subscription form, followed by an iframe that displays that webview URL. I used an iframe to prevent the CSS from the main site to bleed through in the campaign HTML.

<html>
    <head>
        <style>{!! file_get_contents(public_path('css/app.css')) !!}</style>
        <link rel="stylesheet" href="https://cloud.typography.com/6194432/6581412/css/fonts.css"/>
        <title>{{ $campaign->subject }}</title>
    </head>
    <body>
        <header class="w-full mb-4 p-4 sm:p-6 md:px-8 md:py-7 bg-orange-100 border-b-2 border-orange-200 text-xs text-gray-700">
            <div class="max-w-lg mx-auto space-y-2">
                <p>
                    Every two weeks I send out a newsletter like this one, containing lots of interesting stuff for the modern
                    PHP
                    developer.
                </p>
                <p>
                    Subscribe to get the next edition in your mailbox.
                </p>
                @include('front.newsletter.partials.form')
            </div>
        </header>

        <iframe href="{{ $campaign->webViewUrl() }}" />
    </body>
</html>

This would get me 95% of the way there. A challenging problem that I couldn't solve entirely on my own was the janky scroll behavior caused by having an iframe on the page.

Here an example of that "janky" feel:

... to using a web component

Luckily my colleague Seb had an excellent solution: web components. You can think of a web component as a custom HTML tag in which a separate DOM, called the shadow DOM, is rendered. This shadow DOM does not get the CSS of the main page applied to it.

Here's that view that display a subscription form + newsletter again, but this time a web component is used. A bit of JavaScript is needed at the top to configure the web component. The $webview contains the full page content returned by $campaign->webViewUrl().

<html>
    <head>
        <style>{!! file_get_contents(public_path('css/app.css')) !!}</style>
        <link rel="stylesheet" href="https://cloud.typography.com/6194432/6581412/css/fonts.css"/>
        <title>{{ $campaign->subject }}</title>
        <script>
            window.customElements.define('campaign-webview', class NewsletterEmbed extends HTMLElement {
                connectedCallback() {
                    const shadow = this.attachShadow({ mode: 'closed' });
                    shadow.innerHTML = this.getAttribute('contents');
                }
            })
        </script>
    </head>
    <body>
        <header class="w-full mb-4 p-4 sm:p-6 md:px-8 md:py-7 bg-orange-100 border-b-2 border-orange-200 text-xs text-gray-700">
            <div class="max-w-lg mx-auto space-y-2">
                <p>
                    Every two weeks I send out a newsletter like this one, containing lots of interesting stuff for the modern
                    PHP
                    developer.
                </p>
                <p>
                    Subscribe to get the next edition in your mailbox.
                </p>
                @include('front.newsletter.partials.form')
            </div>
        </header>

        <campaign-webview contents="{{ $webview }}"></campaign-webview>
    </body>
</html>

This is pretty neat! It does exactly what we want: the main page's CSS doesn't bleed through, and there's no janky scroll behavior.

To know more about web components and the shadow DOM, read this excellent blog post by Seb.

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

What are your thoughts on "Adding a subscription form to the web views of Mailcoach"?

Comments powered by Laravel Comments
Want to join the conversation? Log in or create an account to post a comment.