Seomate
SEO, mate! It's important. That's why SEOMate provides the tools you need to craft all the meta tags, sitemaps and JSON-LD microdata you need - in one highly configurable, open and friendly package - with a super-light footprint.
Install / Use
/learn @vaersaagod/SeomateREADME
SEOMate plugin for Craft CMS
SEO, mate! It's important. That's why SEOMate provides the tools you need to craft all the meta tags, sitemaps and JSON-LD microdata you need - in one highly configurable, open and friendly package - with a super-light footprint.
SEOMate aims to do less! Unlike other SEO plugins for Craft, there are no control panel settings or fieldtypes. Instead, you configure everything from the plugin's config file, which makes it easy and quick to set up, bootstrap and version control your configuration. All the data is pulled from native Craft fields, which makes for less maintenance over time, and keeps you in control of your data.
Additionally, SEOMate adds a super-awesome SEO/social media preview to your Control Panel. The SEO preview taps into Craft's native Preview Targets, giving your clients a nice and familiar interface for previewing how their content will appear on Google, Facebook and Twitter.

Requirements
This plugin requires Craft CMS 5.0.0 or later.
Installation
To install the plugin, either install it from the plugin store, or follow these instructions:
- Install with composer via
composer require vaersaagod/seomatefrom your project directory. - Install the plugin in the Craft Control Panel under Settings → Plugins, or from the command line via
./craft install/plugin seomate. - For SEOMate to do anything, you need to configure it. But first, continue reading!
SEOMate Overview
SEOMate focuses on providing developers with the tools they need to craft their site's SEO in three main areas; meta data, sitemaps, and JSON-LD microdata.
Meta data
SEOMate doesn't provide any custom field types for entering meta data. Instead, you use native field types that come with Craft, and just tell SEOMate which fields to use.
You do this by configuring field profiles for the different field setups in your site. Sections and category groups can be mapped to these profiles, or the desired profile can be set at the template level.
The key config settings for meta data is fieldProfiles, profileMap, defaultProfile,
defaultMeta and additionalMeta. Refer to the "Adding meta data"
section on how to include the meta data in your page, and how to (optionally) override it at the template level.
Sitemaps
SEOMate lets you create completely configuration based sitemaps for all your content. The sitemaps are automatically updated with new elements, and will automatically be split into multiple sitemaps for scalability.
To enable sitemaps, set the sitemapEnabled config setting to true and configure the
contents of your sitemaps with sitemapConfig. Refer to the "Enabling sitemaps"
section on how to enable and set up your sitemaps.
JSON-LD
SEOMate provides a thin wrapper around the excellent spatie/schema-org
package used for generating JSON-LD data structures. SEOMate exposes the craft.schema
template variable, that directly ties into the fluent Schema API.
This method uses the exact same approach and signature as Rias' Schema plugin. If you're only looking for a way to output JSON-LD, we suggest you use that plugin instead.
SEO preview
SEOMate provides a fancy "SEO Preview" preview target, for any and all elements with URLs, featuring photo realistic approximations of how your content will appear in Google SERPs, or when shared on Facebook, Twitter/X and LinkedIn.

If you don't like the SEO preview, or if you'd like it to only appear for entries in specific sections, check out the previewEnabled config setting.
Things that SEOMate doesn't do...
So much!
Adding meta data
Out of the box, SEOMate doesn't add anything to your markup. To get started, add
{% hook 'seomateMeta' %} to the <head> of your layout. Then, if you haven't already,
create a config file named seomate.php in your config folder alongside your other
Craft config files. This file can use multi-environment configs,
exactly the same as any other config file in Craft, but in the following examples we'll
skip that part to keep things a bit more tidy.
All the config settings are documented in the Configuring section,
and there are quite a few! But to get you going, these are some fundamental concepts:
Field profiles
A field profile in SEOMate is, essentially, a mapping of metadata attributes to the fields that SEOMate should look at for those attributes' metadata values.
To get started, create a profile called "standard" in fieldProfiles, and set that profile as the default
field profile using the defaultProfile setting:
<?php
return [
'defaultProfile' => 'standard',
'fieldProfiles' => [
'standard' => [
'title' => ['seoTitle', 'heading', 'title'],
'description' => ['seoDescription', 'summary'],
'image' => ['seoImage', 'mainImage']
]
],
];
The above tells SEOMate to use the field profile standard to get element metadata from, as a default.
So, everytime a page template that has an element (i.e. entry, category or product) is loaded, SEOMate will
start by checking if that element has a field named seoTitle, and that this field has a value that can be used for
the title meta tag. If a field named seoTitle does not exist – or if it's empty – SEOMate continues to check if
there is a field named heading, and does the same thing. If heading is empty, it checks for title.
And so on, for every key in the field profile.
💡 In addition to field handles, field profiles can also contain functions (i.e. closures), and/or
Twig object templates. For documentation and examples for closures and object templates,
see the fieldProfiles setting!
Mapping different field profiles to elements
Now, let's say we have a section with handle news that has a slightly different field setup than
our other sections, so for entries in that section we want to pull data from some other fields.
We'll add another field profile to fieldProfiles, and make a mapping between the profile and the
section handle in profileMap:
<?php
return [
'defaultProfile' => 'standard',
'fieldProfiles' => [
'standard' => [
'title' => ['seoTitle', 'heading', 'title'],
'description' => ['seoDescription', 'summary'],
'image' => ['seoImage', 'mainImage']
],
'newsprofile' => [
'title' => ['seoTitle', 'heading', 'title'],
'og:title' => ['ogSeo.title', 'ogTitle', 'heading', 'title'],
'description' => ['seoDescription', 'newsExcerpt', 'introText'],
'image' => ['seoImage', 'heroImage', 'newsBlocks.image:image']
'og:image' => ['ogSeo.image', 'ogImage', 'heroImage', 'newsBlocks.image:image']
'twitter:image' => ['twitterImage', 'heroImage', 'newsBlocks.image:image']
]
],
'profileMap' => [
'news' => 'newsprofile',
],
];
The mapping between the "news" section and the profile is simple enough: the key in profileMap can
be the handle for a section, entry type, category group, or Commerce product type, and the value
should be the key for the profile in fieldProfiles that you want to use for matching elements.
In this profile we also we have also used a couple of other SEOMate features.
First, notice that we have chosen to specify a field profile for og:title, og:image
and twitter:image that we didn't have in the default profile. By default, the autofillMap
defines that if no value are set for og:title and twitter:title, we want to autofill those
meta tags with the value from title. So in the standard profile, those values will be
autofilled, while in the newsprofile we choose to customize some of them.
Secondly, we're using a nested object syntax for ogSeo.title and ogSeo.image which could for
instance be used if you have a Content Block field (new in Craft 5.8) with values. Or any other
field type that returns a nested object. It goes as deep as you want, someField.withAnObject.that.has.a.deep.structure.
Thirdly, notice that we can specify to pull a value from a Matrix subfield by using the syntax
matrixFieldHandle.blockTypeHandle:subFieldHandle.
Profile map specificity
In some cases there might be a need to create more specific field profile mappings. For example, you might have
a section with the handle news and a category group with the handle news, and you need their elements to use
different profiles. This can be achieved by using prefixes section: and/or categoryGroup:, e.g.
'profileMap' => [
'section:news' => 'newsprofile', // Will match entries in a section "news"
'categoryGroup:news' => 'newscategoryprofile', // Will match categories in a group "news"
],
Another use case for specific field profiles is if you need a certain entry type to use a specific profile, in which
case the entryType: prefix is the ticket:
'profileMap' => [
'section:news' => 'newsprofile', // Will match entries in a section "news"
'categoryGroup:news' => 'newscategoryprofile', // Will match categories in a group "news"
'pages' => 'pagesprofile',
'entryType:listPage' => 'listpageprofile', // Will match entries with an entry type "listPage"
],
The specific field profiles (i.e. the ones using the {sourceType}: pr
Related Skills
bluebubbles
340.5kUse when you need to send or manage iMessages via BlueBubbles (recommended iMessage integration). Calls go through the generic message tool with channel="bluebubbles".
bear-notes
340.5kCreate, search, and manage Bear notes via grizzly CLI.
claude-ads
1.5kComprehensive paid advertising audit & optimization skill for Claude Code. 186 checks across Google, Meta, YouTube, LinkedIn, TikTok & Microsoft Ads with weighted scoring, parallel agents, and industry templates.
claude-ads
1.5kComprehensive paid advertising audit & optimization skill for Claude Code. 186 checks across Google, Meta, YouTube, LinkedIn, TikTok & Microsoft Ads with weighted scoring, parallel agents, and industry templates.
