How we automatically share new content on social media
Published on by Eric L. Barnes
When we publish a new post here on Laravel News, many things happen in the background for it to be automatically sent out to all the places around the internet. In this post, let's look at how we share it with all the services.
Here is a basic flowchart of what happens on Laravel News when a post is published showing all the services involved:
As you can see, we utilize many different services, but once they are set up, it's not something we've had too much trouble with, and it all happens automatically.
Starting from left to right, let's go through each section and cover how it's setup:
Laravel Notification Channels
Laravel Notification Channels are fantastic, and the community has created many different providers for use. We utilize one for our Twitter account, and another for our read-only Telegram account.
For Telegram, we have an older, but still accurate write-up on auto publishing to Telegram
Here is the code for our PostPublished notification:
class PostPublished extends Notification{ public function via($notifiable) { return [TelegramChannel::class, TwitterChannel::class]; } public function toTelegram($post) { return TelegramMessage::create() ->to('@laravelnews') ->content($post->routes['title'].' https://laravel-news.com/'.$post->routes['uri']); } public function toTwitter($post) { $tweet = $post->routes['title'].' https://laravel-news.com/'.$post->routes['uri']; if ($post->routes['category'] == 'sponsor') { $tweet = $post->routes['title'].' [SPONSOR] https://laravel-news.com/'.$post->routes['uri']; } else if ($handle = $this->twitterHandle($post->routes['twitter_handle'])) { $tweet = $tweet.' posted by '.$handle; } return new TwitterStatusUpdate($tweet); } /** * Add the twitter handle is they are not a mod. */ protected function twitterHandle($twitter) { if (! $twitter) { return false; } if ($twitter and ! Str::startsWith($twitter, '@')) { $twitter = '@'.$twitter; } return $twitter; }}
Emails
We have two primary email lists. One is sent every day, and it includes any new posts and new community links. Then a second list for a weekly email that is sent every Sunday that is currently manually built. You can subscriber to them on our Newsletter page.
The daily is entirely automated and how it works is by utilizing a scheduled console command that queries our Statamic backend for new posts and builds out a complete HTML email in a blade file. From this, we use the Campaign Monitor API to create a draft, then instantly send the email.
protected function schedule(Schedule $schedule){ $schedule->command('ln:daily')->daily()->at('15:00');
Here is the code for doing the actual sending...
protected function sendEmail($posts){ $auth = ['api_key' => config('services.campaign-monitor.key')]; $cm = new CS_REST_Campaigns(null, $auth); // Create a draft from the API $draft = $cm->create(config('services.campaign-monitor.client_id'), [ 'Subject' => $posts[0]['title']->raw(), // first post of the day, usually only one. 'Name' => 'Laravel News Daily ('.date('Y-m-d').')', 'FromName' => 'Laravel News', 'FromEmail' => 'hello@laravel-news.com', 'ReplyTo' => 'hello@laravel-news.com', 'HtmlUrl' => '/full/path/to/daily/html/file', 'ListIDs' => [config('services.campaign-monitor.daily_id')], ]); // grab the draft id and set it to the campaign $cm->set_campaign_id($draft->response); // now send it $cm->send([ 'ConfirmationEmail' => 'hello@laravel-news.com', 'SendDate' => 'immediately', ]);}
RSS Feed
The RSS feed is manually built using the same method as outlined in our tutorial on creating an RSS feed from scratch, but we take it a step further and use a 3rd party service named Feedpress.
By using the third party, we get some stats around RSS readership, which, in theory, is beneficial but not something we check very often.
RSS to Zapier
The next main section utilizes Zapier to read from new items in an RSS feed, then sends the post off to other services.
Facebook and LinkedIn Zaps both get sent to Buffer and then shared from Buffer. We initially used Buffer here because our community links section can have many approved on the same day at the same time, so instead of sharing all those at once, we can utilize more fine-grained scheduling.
For the Mastodon part, I used this tutorial a few weeks ago, and it's been running smoothly since.
JSON Feed
JSON Feeds was a hot topic a few years ago, so we had to have it. This is pretty simple to build, and we have a full tutorial on generating a JSON feed here.
Google News Feed
The final feed is for Google News, which was tricky to set up because they have a lot of restrictions on what they consider news and if you share something to this that they don't consider news, they can block you.
The basics of submitting are you need to give them a special XML feed, but it can only have items published in the past two days and can only be news items.
Here is our controller for setting up all this data from our Statamic backend:
public function news(){ $posts = Collection::find('articles') ->queryEntries() ->where('date', '>', Carbon::now()->subDays(2)->startOfDay()) ->where('date', '<', Carbon::now()) ->where('published', true) ->get() ->toAugmentedArray(); return response()->view('sitemap.google.news', [ 'posts' => $posts, ])->header('Content-Type', 'text/xml');}
Then the Blade view file:
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"> @foreach ($posts as $post) <url> <loc>{{ $post['permalink'] }}</loc> <news:news> <news:publication> <news:name>Laravel News</news:name> <news:language>en</news:language> </news:publication> <news:genres>Blog</news:genres> <news:publication_date>{{ $post['date']->raw()->format("Y-m-d") }}</news:publication_date> <news:title>{{ $post['title'] }}</news:title> @if ($post['tag']->raw()) <news:keywords>{{ implode(',', $post['tag']->raw()) }}</news:keywords> @endif <news:stock_tickers></news:stock_tickers> </news:news> </url> @endforeach</urlset>
Closing
This is how we share with many different services when a new post is published. This setup has been in production for almost a decade and has been solid. While writing this out, I noticed how we could possibly simplify some of these because of newer Notification Channels and could remove the Buffer step totally. Of course, one could also use various APIs directly, but I've found going through Zapier passes on API changes to them instead of something I need to worry about.
If you'd like to follow us at any of the services mentioned, here are our pages:
Eric is the creator of Laravel News and has been covering Laravel since 2012.