aerni/social-links
A Laravel package for adding social media links to your site. Configure profiles, render accessible links with Blade components, and customize icons and URLs with minimal setup.
composer require aerni/social-links
Statamic auto-discovers the addon — there's no service provider to register by hand. If the package ships a publishable config (check the README's install section), do that first:
php artisan vendor:publish --tag=social-links-config
Where to look first
config/social-links.php (or config/social-links.php in the addon's config/ folder) — this is the network list. Everything you can output is driven from here.src/Tags/ if you need to see exactly which keys each item exposes (name, label, url, possibly icon), since that's what your template loops over.First use case: a share bar on an article page
Drop the tag into your entry template, inside the entry scope so it can resolve the current URL:
{{# resources/views/blog/show.antlers.html #}}
<article>
<h1>{{ title }}</h1>
{{ content }}
<aside class="share">
<span>Share</span>
{{ social_links }}
<a href="{{ url }}" target="_blank" rel="noopener noreferrer" aria-label="Share on {{ label }}">
{{ label }}
</a>
{{ /social_links }}
</aside>
</article>
That's the 90% case: install, drop the tag, loop. Everything else in this assessment is polish around that loop.
Before writing your markup, dump the collection once to confirm the key names in your installed version:
{{ social_links }}{{ dump }}{{ /social_links }}
Pull it into a partial early. You will reuse this on blog posts, news, docs, and product pages. One partial keeps the icon markup and rel attributes in a single place:
{{# partials/social_links.antlers.html #}}
{{ social_links }}
<a href="{{ url }}"
target="_blank"
rel="noopener noreferrer"
class="share-link share-link--{{ name }}"
aria-label="Share on {{ label }}">
{{ svg :src="'social/' + name" class="w-5 h-5" aria-hidden="true" }}
</a>
{{ /social_links }}
Then {{ partial:social_links }} anywhere. Keeping the network key as a CSS class (share-link--facebook) lets you brand each button without conditionals.
Filter networks per context. Not every page needs every network — a careers page share bar and a changelog share bar are different. Filter at the template level rather than maintaining two configs:
{{ social_links }}
{{ if name != 'email' }}
<a href="{{ url }}" ...>{{ label }}</a>
{{ /if }}
{{ /social_links }}
If you find yourself filtering the same set in five templates, take the set from the config instead and use the tag with an explicit allow-list if it supports one; otherwise a small partials/social/*.antlers.html per context works fine.
Pass the canonical URL and title explicitly. Don't rely on the tag inferring the current entry, especially if the partial is rendered from a layout or an async region. The most robust pattern is to pass the permalink and title in from the entry:
{{ social_links :url="permalink" :title="title" }}
Check the README for the exact parameter names in your version — but the principle holds: the share URL should be built from the entry's permalink, not from request()->url(). This matters for pagination (/blog?page=2 should still share /blog/my-post) and for any page reachable by multiple paths.
Blade parity. In a Blade view (e.g. a Livewire component or a Mailcoach-adjacent layout) render the tag through Statamic's tag API rather than duplicating URL-building logic:
@foreach (Statamic::tag('social_links')->params([
'url' => $entry->permalink(),
'title' => $entry->get('title'),
])->fetch() as $link)
<a href="{{ $link['url'] }}" target="_blank" rel="noopener noreferrer">
{{ $link['label'] }}
</a>
@endforeach
Add a native-share / copy-link fallback. The addon covers outbound networks only. On mobile, navigator.share is a better default than five buttons. A tiny Alpine island alongside the tag output handles it:
<button
x-data
x-show="navigator.share"
@click="navigator.share({ title: '{{ title }}', url: '{{ permalink }}' })"
>Share…</button>
This keeps the addon as the SSR fallback (works without JS, works with static caching) while modern devices get the OS sheet.
Conditional display in preview. Social links pointing at https://yoursite.test/... or a Statamic preview token URL produce broken share cards. Gate the block:
{{ if ! live_preview && environment == 'production' }}
{{ partial:social_links }}
{{ /if }}
Static caching is a non-issue. The addon renders plain anchors server-side, so it plays nicely with Statamic's static cache and with full-page CDNs. It also loads no third-party scripts — the tracking happens only after the user clicks out, which is why you can ship this without touching your cookie consent banner.
Double-encoded ampersands. Share URLs are query strings full of &. If Antlers escapes the output you'll end up with & inside href, which browsers cope with in HTML but which breaks the moment you interpolate the same value into JavaScript or navigator.share. If you need the raw string, use the raw modifier in your Antlers version and escape manually where it's rendered into markup.
Never build your own share URLs next to this. The temptation is to add "one more network" by hand. The moment you do, you own rawurlencode() of the title, the platform-specific parameter names (text vs title vs summary), and the URL length limits. Add the network to the config file instead — that's the intended extension point, and it keeps the name keys consistent across the loop.
Config caching on deploy. After publishing and editing the network list, php artisan config:cache (standard in most deploy scripts) will freeze it. Locally, remember php artisan config:clear when a network you removed is still showing. This is the single most common "the addon is broken" moment.
rel and target are on you. The package outputs URLs, not anchors. Every generated link needs rel="noopener noreferrer" — a partial fixes this once, but copy-pasted inline markup will eventually miss it. While you're there, set aria-labels; a row of bare SVG icons is invisible to screen readers.
No icons are bundled. The addon generates links, not logos. Pair it with your existing icon set (Heroicons, Simple Icons SVG sprites, or {{ svg }}) and key them off name. Watch the naming mismatch: if the config uses twitter and you've rebranded to X in your icon folder, share-link--twitter looks for the wrong file — either keep the config key as twitter and map in CSS, or add the network under both keys.
Live Preview and multisite URLs. In Live Preview the share URL will be the preview URL, which is useless for sharing. On multisite, confirm the tag resolves the current site's permalink and not the default site's — if it doesn't, pass :url="permalink" explicitly, which always resolves in the active site's scope.
Local development looks broken. Pasting http://mysite.test/blog/foo into Facebook's debugger produces nothing useful. Don't conclude the addon is generating bad URLs — check the markup, not the share preview, while developing, and validate against staging.
Email links need length discipline. mailto: share targets put title and URL into the subject/body. Long CMS titles get truncated in some clients. If email sharing is prominent on your site, pass a trimmed title rather than the full title field.
Extending beyond the tag. If you need behaviour the tag doesn't have — analytics events per network, a network gated behind a feature flag, or per-entry network selection via a fieldtype — the cleanest path is a Blade/Antlers partial that wraps Statamic::tag('social_links'), then a small field or config toggle to filter it. Forking the addon is rarely necessary; it's a thin URL builder and the config file is its real API surface.
How can I help you explore Laravel packages today?