A few of my recent projects—like Cooking Vinyl Compilations and ReadABooker—aim to earn a little money via affiliate links. That only works if people actually find the pages, share them, and get decent previews in social apps. In other words: the boring, fragile glue of SEO and social meta tags matters.
As I lined up a couple more sites in the same vein, I noticed I was writing very similar code again and again: take an object with title
, url
, image
, description
, and spray out the right <meta>
tags for Google, Twitter, Facebook, iMessage, Slack, and so on. It’s fiddly, easy to get 80% right, and annoying to maintain across projects. So I pulled it into a small Moo role—MooX::Role::SEOTags
—that any page-ish class can consume and just emit the right tags.
What are these tags and why should you care?
When someone shares your page, platforms read a handful of standardised tags to decide what to show in the preview:
-
Open Graph (
og:*
) — The de-facto standard for title, description, URL, image, and type. Used by Facebook, WhatsApp, Slack, iMessage and others. -
Twitter Cards (
twitter:*
) — Similar idea for Twitter/X; the common pattern istwitter:card=summary_large_image
plus title/description/image. -
Classic SEO tags —
<title>
,<meta name="description">
, and a canonical URL tell search engines what the page is about and which URL is the “official” one.
MooX::Role::SEOTags gives you one method that renders all of that, consistently, from your object’s attributes.
For more information about OpenGraph, see ogp.me.
What it does
MooX::Role::SEOTags
adds a handful of attributes and helper methods so any Moo (or Moose) class can declare the bits of information that power social previews and search snippets, then render them as HTML.
- Open Graph tags (
og:title
,og:type
,og:url
,og:image
, etc.) - Twitter Card tags (
twitter:card
,twitter:title
,twitter:description
,twitter:image
) - Standard SEO:
<title>
, metadescription
, canonical<link rel="canonical">
- A single method to render the whole block with one call
- But also individual methods to give you more control over tag placement
That’s the whole job: define attributes → get valid tags out.
Quick start
Install the role using your favourite CPAN module installation tool.
cpanm MooX::Role::SEOTags
Then, in your code, you will need to add some attributes or methods that define the pieces of information the role needs. The role requires four pieces of information – og_title
, og_description
, og_url
and og_type
– and og_image
is optional (but highly recommended).
So a simple class might look like this:
package MyPage;
use Moo;
with 'MooX::Role::SEOTags';
# minimal OG fields
has og_title => (is => 'ro', required => 1);
has og_type => (is => 'ro', required => 1); # e.g. 'article'
has og_url => (is => 'ro', required => 1);
has og_description => (is => 'ro');
# optional niceties
has og_image => (is => 'ro'); # absolute URL
has twitter_card => (is => 'ro', default => sub { 'summary_large_image' });
1;
And then you create the object:
my $page = MyPage->new(
og_title => 'How to Title a Title',
og_type => 'article',
og_url => 'https://example.com/post/title',
og_image => 'https://example.com/img/hero.jpg',
og_description => 'A short, human description of the page.',
);
Then you can call the various *_tag
and *_tags
methods to get the correct HTML for the various tags.
The easiest option is to just produce all of the tags in one go:
say $page->tags;
But, for more control, you can call individual methods:
say $page->title_tag;
say $page->canonical_tag;
say $page->og_tags;
# etc...
Depending on which combination of method calls you use, the output will look something like this:
<title>How to Title a Title</title>
<meta name="description" content="A short, human description of the page.">
<link rel="canonical" href="https://example.com/post/title">
<meta property="og:title" content="How to Title a Title">
<meta property="og:type" content="article">
<meta property="og:url" content="https://example.com/post/title">
<meta property="og:image" content="https://example.com/img/hero.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="How to Title a Title">
<meta name="twitter:description" content="A short, human description of the page.">
<meta name="twitter:image" content="https://example.com/img/hero.jpg">
In many cases, you’ll be pulling the data from a database and displaying the output using a templating system like the Template Toolkit.
my $tt = Template->new;
my $object = $resultset->find({ slug => $some_slug });
$tt->process('page.tt', { object => $object }, "$some_slug/index.html");
In this case, you’d just add a single call to the
of your page template.<head>
<!-- lots of other HTML -->
[% object.tags %]
</head>
A note if you used my earlier Open Graph role
If you spotted MooX::Role::OpenGraph
arrive on MetaCPAN recently: SEOTags
is the “grown-up” superset. It does Open Graph and Twitter and standard tags, so you only need one role. The old module is scheduled for deletion from MetaCPAN.
SEO tags and JSON-LD
These tags are only one item in the SEO toolkit that you’d use to increase the visibility of your website. Another useful tool is JSON-LD – which allows you to add a machine-readable description of the information that your page contains. Google loves JSON-LD. And it just happens that I have another Moo role called MooX::Role::JSON_LD which makes it easy to add that to your page too. I wrote a blog post about using that earlier this year.
In conclusion
If you’ve got even one page that deserves to look smarter in search and social previews, now’s the moment. Pick a page, add a title, description, canonical URL and a decent image, and let MooX::Role::SEOTags
spit out the right tags every time (and, if you fancy richer results, pair it with MooX::Role::JSON_LD
). Share the link in Slack/WhatsApp/Twitter to preview it, fix anything that looks off, and ship. It’s a 20-minute tidy-up that can lift click-throughs for years—so go on, give one of your pages a quick SEO spruce-up today.
The post Easy SEO for lazy programmers first appeared on Perl Hacks.
Top comments (0)