+
+
+
diff --git a/docs/docs/.vitepress/theme/img/craft-cms-logo.svg b/docs/docs/.vitepress/theme/img/craft-cms-logo.svg
new file mode 100644
index 000000000..657256a0e
--- /dev/null
+++ b/docs/docs/.vitepress/theme/img/craft-cms-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/docs/.vitepress/theme/img/moz-logo.svg b/docs/docs/.vitepress/theme/img/moz-logo.svg
new file mode 100644
index 000000000..77aa2de9d
--- /dev/null
+++ b/docs/docs/.vitepress/theme/img/moz-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/docs/.vitepress/theme/index.ts b/docs/docs/.vitepress/theme/index.ts
index 66de69c4d..6293e9cf4 100644
--- a/docs/docs/.vitepress/theme/index.ts
+++ b/docs/docs/.vitepress/theme/index.ts
@@ -3,6 +3,7 @@ import {h, watch} from 'vue'
import './custom.css'
import NYSLogo from './NYSLogo.vue';
+import UsedByLogos from './UsedByLogos.vue';
// Could also come from .env
const GA_ID = 'UA-69117511-1';
@@ -15,7 +16,9 @@ export default {
}
)
},
- enhanceApp: (ctx) => {
+ enhanceApp: ({ app, router }) => {
+ app.component('UsedByLogos', UsedByLogos);
+
// Google analytics integration
if (import.meta.env.PROD && GA_ID && typeof window !== 'undefined') {
(function (i, s, o, g, r, a, m) {
@@ -33,7 +36,7 @@ export default {
ga('create', GA_ID, 'auto')
ga('set', 'anonymizeIp', true)
// Send a page view any time the route changes
- watch(ctx.router.route, (newValue, oldValue) => {
+ watch(router.route, (newValue, oldValue) => {
ga('set', 'page', newValue.path)
ga('send', 'pageview')
})
diff --git a/docs/docs/advanced.md b/docs/docs/advanced.md
index 47ba685ef..19c6c6f17 100644
--- a/docs/docs/advanced.md
+++ b/docs/docs/advanced.md
@@ -2,23 +2,30 @@
title: Advanced Usage
description: Advanced Usage documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
---
+
# Advanced Usage
+Using the debug toolbar, managing config settings, events for PHP developers, bundle / container settings, and using the headless SPA API.
+
## Debug Toolbar
-SEOmatic included a debug panel for the [Yii2 Debug Toolbar](https://nystudio107.com/blog/profiling-your-website-with-craft-cms-3s-debug-toolbar) that allows you to inspect & debug your SEO data.
+SEOmatic includes a debug panel for the [Yii2 Debug Toolbar](https://nystudio107.com/blog/profiling-your-website-with-craft-cms-3s-debug-toolbar) that allows you to inspect and debug your SEO data.
-![Screenshot](./resources/screenshots/seomatic-yii2-debug-toolbar.png)
+![Screenshot of Craft’s debug toolbar with an SEOmatic section at the far right](./resources/screenshots/seomatic-yii2-debug-toolbar.png)
The debug panel displays debug information about the tags SEOmatic generates, as well as the variables it uses to do so.
You can view the **Combined** composed SEO data, or the discrete SEO data coming from the layered **Entry SEO**, **Content SEO**, and **Global SEO** settings.
+The SEOmatic Debug Toolbar panel provides valuable debugging information if you have the Yii2 Debug Toolbar enabled, but it does add some overhead as well.
+
+If you're doing performance profiling, you can keep the Yii2 Debug Toolbar enabled, but disable the SEOmatic panel via **Plugin Settings → Advanced → SEOmatic Debug Toolbar Panel**.
+
### Tags
Tags are objects that represent rendered HTML tags the in the webpage. Tags are grouped together into containers for organizational purposes.
-![Screenshot](./resources/screenshots/seomatic-debug-tags.png)
+![Screenshot of the expanded debug toolbar open to the SEOmatic section, which has tabs for Tags and Variables, a visualization of the SEO cascade, and a listing of meta tag properties and how they’re rendered](./resources/screenshots/seomatic-debug-tags.png)
You can inspect the **Properties** of the tags in each container, as well as the corresponding **Parsed Properties** after they have been rendered as Twig.
@@ -47,7 +54,7 @@ Tag property example:
Variables are used throughout SEOmatic when rendering tags, or controlling how tags are rendered. Tag properties often reference these variables via Twig expressions.
-![Screenshot](./resources/screenshots/seomatic-debug-variables.png)
+![Screenshot of the SEOmatic debug toolbar section examining meta global vars, where the title text includes Twig usage tips](./resources/screenshots/seomatic-debug-variables.png)
You can inspect the **Properties** of the variables, as well as the corresponding **Parsed Properties** after they have been rendered as Twig.
@@ -56,6 +63,7 @@ You can expand and sub-properties of nested properties by clicking on them.
When hovering the cursor over any property, a clipboard icon will appear that when clicked on copies to the clipboard example code of how to get/set values for that particular property via Twig.
Variable example:
+
```twig
{#-- Get the value --#}
{% set value = seomatic.meta.seoImage %}
@@ -67,97 +75,110 @@ Variable example:
SEOmatic supports the standard `config.php` multi-environment friendly config file for the plugin settings. Just copy the `config.php` to your Craft `config/` directory as `seomatic.php` and you can configure the settings in a multi-environment friendly way.
-These are the same settings that are configured in the **Plugin Settings** in the Control Panel.
+These are the same settings that are configured in the **Plugin Settings** in the control panel.
## Events
### IncludeContainerEvent
- const EVENT_INCLUDE_CONTAINER = 'includeContainer';
-
The event that is triggered when a container is about to be included.
```php
use nystudio107\seomatic\events\IncludeContainerEvent;
use nystudio107\seomatic\base\Container;
use yii\base\Event;
-Event::on(Container::class, Container::EVENT_INCLUDE_CONTAINER, function(IncludeContainerEvent $e) {
- $e->include = false;
-});
+
+Event::on(
+ Container::class,
+ Container::EVENT_INCLUDE_CONTAINER,
+ function(IncludeContainerEvent $event) {
+ $event->include = false;
+ }
+);
```
### InvalidateContainerCachesEvent
- const EVENT_INVALIDATE_CONTAINER_CACHES = 'invalidateContainerCaches';
-
The event that is triggered when SEOmatic is about to clear its meta container caches
```php
use nystudio107\seomatic\events\InvalidateContainerCachesEvent;
use nystudio107\seomatic\services\MetaContainers;
use yii\base\Event;
-Event::on(MetaContainers::class, MetaContainers::EVENT_INVALIDATE_CONTAINER_CACHES, function(InvalidateContainerCachesEvent $e) {
- // Container caches are about to be cleared
-});
+
+Event::on(
+ MetaContainers::class,
+ MetaContainers::EVENT_INVALIDATE_CONTAINER_CACHES,
+ function(InvalidateContainerCachesEvent $event) {
+ // Container caches are about to be cleared
+ }
+);
```
### IncludeSitemapEntryEvent
- const EVENT_INCLUDE_SITEMAP_ENTRY = 'IncludeSitemapEntryEvent';
-
The event that is triggered when an entry is about to be included in a sitemap.
```php
- use nystudio107\seomatic\events\IncludeSitemapEntryEvent;
- use nystudio107\seomatic\helpers\Sitemap;
- use yii\base\Event;
- Event::on(Sitemap::class, Sitemap::EVENT_INCLUDE_SITEMAP_ENTRY, function(IncludeSitemapEntryEvent $e) {
- $e->include = false;
- });
+use nystudio107\seomatic\events\IncludeSitemapEntryEvent;
+use nystudio107\seomatic\helpers\Sitemap;
+use yii\base\Event;
+
+Event::on(
+ Sitemap::class,
+ Sitemap::EVENT_INCLUDE_SITEMAP_ENTRY,
+ function(IncludeSitemapEntryEvent $event) {
+ $event->include = false;
+ }
+);
```
### RegisterSitemapUrlsEvent
- const EVENT_REGISTER_SITEMAP_URLS = 'registerSitemapUrls';
-
The event that is triggered when registering additional URLs for a sitemap.
```php
use nystudio107\seomatic\events\RegisterSitemapUrlsEvent;
use nystudio107\seomatic\models\SitemapCustomTemplate;
use yii\base\Event;
-Event::on(SitemapCustomTemplate::class, SitemapCustomTemplate::EVENT_REGISTER_SITEMAP_URLS, function(RegisterSitemapUrlsEvent $e) {
- $e->sitemaps[] = [
- 'loc' => $url,
- 'changefreq' => $changeFreq,
- 'priority' => $priority,
- 'lastmod' => $lastMod,
- ];
-});
+
+Event::on(
+ SitemapCustomTemplate::class,
+ SitemapCustomTemplate::EVENT_REGISTER_SITEMAP_URLS,
+ function(RegisterSitemapUrlsEvent $event) {
+ $event->sitemaps[] = [
+ 'loc' => $url,
+ 'changefreq' => $changeFreq,
+ 'priority' => $priority,
+ 'lastmod' => $lastMod,
+ ];
+ }
+);
```
### RegisterSitemapsEvent
- const EVENT_REGISTER_SITEMAPS = 'registerSitemaps';
-
The event that is triggered when registering additional sitemaps for the sitemap index.
```php
use nystudio107\seomatic\events\RegisterSitemapsEvent;
use nystudio107\seomatic\models\SitemapIndexTemplate;
use yii\base\Event;
-Event::on(SitemapIndexTemplate::class, SitemapIndexTemplate::EVENT_REGISTER_SITEMAPS, function(RegisterSitemapsEvent $e) {
- $e->sitemaps[] = [
- 'loc' => $url,
- 'lastmod' => $lastMod,
- ];
-});
+
+Event::on(
+ SitemapIndexTemplate::class,
+ SitemapIndexTemplate::EVENT_REGISTER_SITEMAPS,
+ function(RegisterSitemapsEvent $event) {
+ $event->sitemaps[] = [
+ 'loc' => $url,
+ 'lastmod' => $lastMod,
+ ];
+ }
+);
```
### RegisterComponentTypesEvent
- const EVENT_REGISTER_SEO_ELEMENT_TYPES = 'registerSeoElementTypes';
-
The event that is triggered when registering SeoElement types
SeoElement types must implement [[SeoElementInterface]]
@@ -167,7 +188,8 @@ use nystudio107\seomatic\services\SeoElements;
use craft\events\RegisterComponentTypesEvent;
use yii\base\Event;
-Event::on(SeoElements::class,
+Event::on(
+ SeoElements::class,
SeoElements::EVENT_REGISTER_SEO_ELEMENT_TYPES,
function(RegisterComponentTypesEvent $event) {
$event->types[] = MySeoElement::class;
@@ -177,24 +199,31 @@ Event::on(SeoElements::class,
### AddDynamicMetaEvent
- const EVENT_ADD_DYNAMIC_META = 'addDynamicMeta';
-
The event that is triggered when SEOmatic has included the standard meta containers, and gives your plugin/module the chance to add whatever custom dynamic meta items you like
```php
use nystudio107\seomatic\events\AddDynamicMetaEvent;
use nystudio107\seomatic\helpers\DynamicMeta;
use yii\base\Event;
-Event::on(DynamicMeta::class, DynamicMeta::EVENT_ADD_DYNAMIC_META, function(AddDynamicMetaEvent $e) {
- // Add whatever dynamic meta items to the containers as you like
-});
+use nystudio107\seomatic\Seomatic;
+
+Event::on(
+ DynamicMeta::class,
+ DynamicMeta::EVENT_ADD_DYNAMIC_META,
+ function(AddDynamicMetaEvent $event) {
+ // Add whatever dynamic meta items to the containers as you like
+ Seomatic::$plugin->getMetaContainers()
+ ->metaGlobalVars
+ ->seoDescription = "This description overrides any others!";
+ }
+);
```
## Meta Bundle / Container Settings
-The directory `vendor/nystudio107/seomatic/src/seomatic-config` contains a number of files that are used when initially configuring SEOmatic.
+The [`vendor/nystudio107/seomatic/src/seomatic-config`](https://github.com/nystudio107/craft-seomatic/tree/develop/src/seomatic-config) directory contains a number of files that are used when initially configuring SEOmatic.
-![Screenshot](./resources/screenshots/seomatic-seomatic-config.png)
+![Screenshot of a Finder window displaying the contents of the seomatic-config directory, whose visible top-level folders are categorymeta, entrymeta, and globalmeta](./resources/screenshots/seomatic-seomatic-config.png)
You can copy this entire directory to your Craft `config/` directory, and customize the files to your heart’s content. SEOmatic will first look in the `config/` directory for any given file, and then fall back on its own internal `seomatic-config` files.
@@ -204,11 +233,11 @@ You can bump the `Bundle.php`'s `bundleVersion` setting if you want it to re-rea
## Headless SPA API
-SEOmatic allows you to fetch the meta information for any page via a controller API endpoint, so you can render the metadata via a frontend framework like VueJS or React.
+SEOmatic allows you to fetch the meta information for any page via a controller API endpoint, so you can render the metadata via a front-end framework like VueJS or React.
### GraphQL Query support
-To retrieve SEOmatic container data through the native [GraphQL in Craft CMS 3.3](https://docs.craftcms.com/v3/graphql.html#sending-api-requests) or the [CraftQL plugin](https://github.com/markhuot/craftql), use the `seomatic` field in your GraphQL query. Each parameter will return that container’s data, ready for insertion into the DOM.
+To retrieve SEOmatic container data through [GraphQL in Craft CMS 3](https://craftcms.com/docs/3.x/graphql.html#sending-api-requests), use the `seomatic` field in your GraphQL query. Each parameter will return that container’s data, ready for insertion into the DOM.
#### Stand-alone GraphQL queries
@@ -217,12 +246,12 @@ You must as least pass in the URI you want metadata for:
```graphql
{
seomatic (uri: "/") {
- metaTitleContainer
- metaTagContainer
- metaLinkContainer
- metaScriptContainer
- metaJsonLdContainer
- metaSiteVarsContainer
+ metaTitleContainer
+ metaTagContainer
+ metaLinkContainer
+ metaScriptContainer
+ metaJsonLdContainer
+ metaSiteVarsContainer
}
}
```
@@ -232,12 +261,12 @@ You must as least pass in the URI you want metadata for:
```graphql
{
seomatic (uri: "/", siteId: 2) {
- metaTitleContainer
- metaTagContainer
- metaLinkContainer
- metaScriptContainer
- metaJsonLdContainer
- metaSiteVarsContainer
+ metaTitleContainer
+ metaTagContainer
+ metaLinkContainer
+ metaScriptContainer
+ metaJsonLdContainer
+ metaSiteVarsContainer
}
}
```
@@ -247,12 +276,12 @@ You must as least pass in the URI you want metadata for:
```graphql
{
seomatic (uri: "/", site: "french") {
- metaTitleContainer
- metaTagContainer
- metaLinkContainer
- metaScriptContainer
- metaJsonLdContainer
- metaSiteVarsContainer
+ metaTitleContainer
+ metaTagContainer
+ metaLinkContainer
+ metaScriptContainer
+ metaJsonLdContainer
+ metaSiteVarsContainer
}
}
```
@@ -262,12 +291,12 @@ You must as least pass in the URI you want metadata for:
```graphql
{
seomatic (uri: "/", asArray: true) {
- metaTitleContainer
- metaTagContainer
- metaLinkContainer
- metaScriptContainer
- metaJsonLdContainer
- metaSiteVarsContainer
+ metaTitleContainer
+ metaTagContainer
+ metaLinkContainer
+ metaScriptContainer
+ metaJsonLdContainer
+ metaSiteVarsContainer
}
}
```
@@ -280,12 +309,12 @@ This is useful if you’re using Next.js, Nuxt.js, Gatsby, Gridsome, or anything
```graphql
{
seomatic (uri: "/", environment: staging) {
- metaTitleContainer
- metaTagContainer
- metaLinkContainer
- metaScriptContainer
- metaJsonLdContainer
- metaSiteVarsContainer
+ metaTitleContainer
+ metaTagContainer
+ metaLinkContainer
+ metaScriptContainer
+ metaJsonLdContainer
+ metaSiteVarsContainer
}
}
```
@@ -295,15 +324,13 @@ This is useful if you are using a single Craft CMS instance to render metadata f
Valid values are `local` for local development, `staging` for staging, and `live` for live production.
-![Screenshot](./resources/screenshots/seomatic-craftql-query.png)
+![Screenshot of CraftQL for some reason demonstrating a GraphQL query](./resources/screenshots/seomatic-craftql-query.png)
#### Piggybacking GraphQL queries
You can also piggyback on an entries query, to return all of your data for an entry as well as the SEOmatic metadata in one request.
-**N.B.:** This requires using either Craft CMS 3.4 or later, or the CraftQL plugin to work.
-
-Native Craft CMS GraphQL:
+Craft CMS GraphQL:
```graphql
{
@@ -322,29 +349,9 @@ Native Craft CMS GraphQL:
}
```
-CraftQL Plugin:
-
-```graphql
-{
- entry(section: homepage) {
- id
- title
- ... on Homepage {
- seomatic {
- metaTitleContainer
- metaTagContainer
- metaLinkContainer
- metaScriptContainer
- metaJsonLdContainer
- }
- }
- }
-}
-```
-
In this case, no arguments are passed in, because the URI and siteId will be taken from the parent Entry element. But you can pass in the `asArray` argument too:
-Native Craft CMS GraphQL:
+Craft CMS GraphQL:
```graphql
{
@@ -363,31 +370,11 @@ Native Craft CMS GraphQL:
}
```
-CraftQL Plugin:
-
-```graphql
-{
- entry(section: homepage) {
- id
- title
- ... on Homepage {
- seomatic(asArray: true) {
- metaTitleContainer
- metaTagContainer
- metaLinkContainer
- metaScriptContainer
- metaJsonLdContainer
- }
- }
- }
-}
-```
-
### Frontend Templates GraphQL queries
-SEOmatic an provide you with the frontend templates such as `robots.txt`, `humans.txt`, etc. as well:
+SEOmatic an provide you with the front-end templates such as `robots.txt`, `humans.txt`, etc. as well:
-![Screenshot](./resources/screenshots/seomatic-graphql-frontendtemplates-query.png)
+![Screenshot of Craft’s GraphQL explorer querying SEOmatic’s `frontendTemplates`](./resources/screenshots/seomatic-graphql-frontendtemplates-query.png)
```graphql
{
@@ -408,13 +395,13 @@ Arguments:
`site:` String - Optional - The site handle to resolve the sitemap for.
-`type:` String - The frontend container type, which can be `robots`, `humans`, `security`, or `ads`
+`type:` String - The front-end container type, which can be `robots`, `humans`, `security`, or `ads`
#### Sitemap GraphQL queries
SEOmatic can provide you with the sitemap data via GraphQL as well.
-![Screenshot](./resources/screenshots/seomatic-graphql-sitemaps-query.png)
+![Screenshot of Craft’s GraphQL explorer querying SEOmatic’s `sitemapIndexes`, `sitemaps`, and `sitemapStyles`](./resources/screenshots/seomatic-graphql-sitemaps-query.png)
SEOmatic allows you to query for `sitemapIndexes`:
@@ -469,7 +456,7 @@ SEOmatic also allows you to query for `sitemapStyles`:
```graphql
{
seomatic {
- sitemapStyles {
+ sitemapStyles {
filename
contents
}
@@ -481,7 +468,9 @@ This returns the [XSL stylesheet](https://www.w3.org/Style/XSL/WhatIsXSL.html) t
### Meta Container API Endpoints
-**N.B.:** Anonymous access to the Meta Container endpoints are disabled by default; you’ll need to enable them in SEOmatic → Plugin Settings → Endpoints
+::: tip
+Anonymous access to the Meta Container endpoints are disabled by default; enable them in **SEOmatic** → **Plugin Settings** → **Endpoints**.
+:::
To get all of the meta containers for a given URI, the controller action is:
@@ -516,287 +505,290 @@ Should you wish to have the items in the meta containers return as an array of d
```
Which will return the data in array form:
+
+::: details Expand Result
```json
{
- "MetaTitleContainer": {
- "title": {
- "title": "[devMode] Craft3 | Homepage"
- }
+ "MetaTitleContainer": {
+ "title": {
+ "title": "[devMode] Craft3 | Homepage"
+ }
+ },
+ "MetaTagContainer": {
+ "generator": {
+ "content": "SEOmatic",
+ "name": "generator"
+ },
+ "referrer": {
+ "content": "no-referrer-when-downgrade",
+ "name": "referrer"
},
- "MetaTagContainer": {
- "generator": {
- "content": "SEOmatic",
- "name": "generator"
+ "robots": {
+ "content": "all",
+ "name": "robots"
+ }
+ },
+ "MetaLinkContainer": {
+ "canonical": {
+ "href": "http://craft3.test/",
+ "rel": "canonical"
+ },
+ "author": {
+ "href": "/humans.txt",
+ "rel": "author",
+ "type": "text/plain"
+ },
+ "alternate": {
+ "href": "http://craft3.test/",
+ "hreflang": "es",
+ "rel": "alternate"
+ }
+ },
+ "MetaScriptContainer": [],
+ "MetaJsonLdContainer": {
+ "WebPage": {
+ "@context": "http://schema.org",
+ "@type": "WebPage",
+ "image": {
+ "@type": "ImageObject",
+ "height": "804",
+ "width": "1200"
+ },
+ "inLanguage": "en-us",
+ "mainEntityOfPage": "http://craft3.test/",
+ "name": "Homepage",
+ "url": "http://craft3.test/"
+ },
+ "BreadcrumbList": {
+ "@context": "http://schema.org",
+ "@type": "BreadcrumbList",
+ "description": "Breadcrumbs list",
+ "itemListElement": [
+ {
+ "@type": "ListItem",
+ "name": "Homepage",
+ "item": "http://craft3.test/",
+ "position": 1
+ }
+ ],
+ "name": "Breadcrumbs"
+ }
+ },
+ "MetaSiteVarsContainer": {
+ "siteName": "woof",
+ "identity": {
+ "siteType": "Organization",
+ "siteSubType": "LocalBusiness",
+ "siteSpecificType": "none",
+ "computedType": "LocalBusiness",
+ "genericName": "",
+ "genericAlternateName": "",
+ "genericDescription": "",
+ "genericUrl": "$HOME",
+ "genericImage": null,
+ "genericImageWidth": "229",
+ "genericImageHeight": "220",
+ "genericImageIds": [
+ "25"
+ ],
+ "genericTelephone": "",
+ "genericEmail": "",
+ "genericStreetAddress": "",
+ "genericAddressLocality": "",
+ "genericAddressRegion": "",
+ "genericPostalCode": "",
+ "genericAddressCountry": "",
+ "genericGeoLatitude": "",
+ "genericGeoLongitude": "",
+ "personGender": "Male",
+ "personBirthPlace": "",
+ "organizationDuns": "",
+ "organizationFounder": "",
+ "organizationFoundingDate": "",
+ "organizationFoundingLocation": "",
+ "organizationContactPoints": "",
+ "corporationTickerSymbol": "",
+ "localBusinessPriceRange": "$",
+ "localBusinessOpeningHours": [
+ {
+ "open": null,
+ "close": null
},
- "referrer": {
- "content": "no-referrer-when-downgrade",
- "name": "referrer"
+ {
+ "open": null,
+ "close": null
},
- "robots": {
- "content": "all",
- "name": "robots"
- }
- },
- "MetaLinkContainer": {
- "canonical": {
- "href": "http://craft3.test/",
- "rel": "canonical"
+ {
+ "open": null,
+ "close": null
},
- "author": {
- "href": "/humans.txt",
- "rel": "author",
- "type": "text/plain"
+ {
+ "open": null,
+ "close": null
},
- "alternate": {
- "href": "http://craft3.test/",
- "hreflang": "es",
- "rel": "alternate"
- }
- },
- "MetaScriptContainer": [],
- "MetaJsonLdContainer": {
- "WebPage": {
- "@context": "http://schema.org",
- "@type": "WebPage",
- "image": {
- "@type": "ImageObject",
- "height": "804",
- "width": "1200"
- },
- "inLanguage": "en-us",
- "mainEntityOfPage": "http://craft3.test/",
- "name": "Homepage",
- "url": "http://craft3.test/"
+ {
+ "open": null,
+ "close": null
+ },
+ {
+ "open": null,
+ "close": null
},
- "BreadcrumbList": {
- "@context": "http://schema.org",
- "@type": "BreadcrumbList",
- "description": "Breadcrumbs list",
- "itemListElement": [
- {
- "@type": "ListItem",
- "name": "Homepage",
- "item": "http://craft3.test/",
- "position": 1
- }
- ],
- "name": "Breadcrumbs"
+ {
+ "open": null,
+ "close": null
}
+ ],
+ "restaurantServesCuisine": "",
+ "restaurantMenuUrl": "",
+ "restaurantReservationsUrl": ""
},
- "MetaSiteVarsContainer": {
- "siteName": "woof",
- "identity": {
- "siteType": "Organization",
- "siteSubType": "LocalBusiness",
- "siteSpecificType": "none",
- "computedType": "LocalBusiness",
- "genericName": "",
- "genericAlternateName": "",
- "genericDescription": "",
- "genericUrl": "$HOME",
- "genericImage": null,
- "genericImageWidth": "229",
- "genericImageHeight": "220",
- "genericImageIds": [
- "25"
- ],
- "genericTelephone": "",
- "genericEmail": "",
- "genericStreetAddress": "",
- "genericAddressLocality": "",
- "genericAddressRegion": "",
- "genericPostalCode": "",
- "genericAddressCountry": "",
- "genericGeoLatitude": "",
- "genericGeoLongitude": "",
- "personGender": "Male",
- "personBirthPlace": "",
- "organizationDuns": "",
- "organizationFounder": "",
- "organizationFoundingDate": "",
- "organizationFoundingLocation": "",
- "organizationContactPoints": "",
- "corporationTickerSymbol": "",
- "localBusinessPriceRange": "$",
- "localBusinessOpeningHours": [
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- }
- ],
- "restaurantServesCuisine": "",
- "restaurantMenuUrl": "",
- "restaurantReservationsUrl": ""
+ "creator": {
+ "siteType": "Organization",
+ "siteSubType": "LocalBusiness",
+ "siteSpecificType": "none",
+ "computedType": "LocalBusiness",
+ "genericName": "",
+ "genericAlternateName": "",
+ "genericDescription": "",
+ "genericUrl": "",
+ "genericImage": null,
+ "genericImageWidth": "1340",
+ "genericImageHeight": "596",
+ "genericImageIds": [
+ "24"
+ ],
+ "genericTelephone": "",
+ "genericEmail": "",
+ "genericStreetAddress": "",
+ "genericAddressLocality": "",
+ "genericAddressRegion": "",
+ "genericPostalCode": "",
+ "genericAddressCountry": "",
+ "genericGeoLatitude": "",
+ "genericGeoLongitude": "",
+ "personGender": "Male",
+ "personBirthPlace": "",
+ "organizationDuns": "",
+ "organizationFounder": "",
+ "organizationFoundingDate": "",
+ "organizationFoundingLocation": "",
+ "organizationContactPoints": "",
+ "corporationTickerSymbol": "",
+ "localBusinessPriceRange": "$",
+ "localBusinessOpeningHours": [
+ {
+ "open": null,
+ "close": null
},
- "creator": {
- "siteType": "Organization",
- "siteSubType": "LocalBusiness",
- "siteSpecificType": "none",
- "computedType": "LocalBusiness",
- "genericName": "",
- "genericAlternateName": "",
- "genericDescription": "",
- "genericUrl": "",
- "genericImage": null,
- "genericImageWidth": "1340",
- "genericImageHeight": "596",
- "genericImageIds": [
- "24"
- ],
- "genericTelephone": "",
- "genericEmail": "",
- "genericStreetAddress": "",
- "genericAddressLocality": "",
- "genericAddressRegion": "",
- "genericPostalCode": "",
- "genericAddressCountry": "",
- "genericGeoLatitude": "",
- "genericGeoLongitude": "",
- "personGender": "Male",
- "personBirthPlace": "",
- "organizationDuns": "",
- "organizationFounder": "",
- "organizationFoundingDate": "",
- "organizationFoundingLocation": "",
- "organizationContactPoints": "",
- "corporationTickerSymbol": "",
- "localBusinessPriceRange": "$",
- "localBusinessOpeningHours": [
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- },
- {
- "open": null,
- "close": null
- }
- ],
- "restaurantServesCuisine": "",
- "restaurantMenuUrl": "",
- "restaurantReservationsUrl": ""
+ {
+ "open": null,
+ "close": null
},
- "twitterHandle": "",
- "facebookProfileId": "",
- "facebookAppId": "",
- "googleSiteVerification": "",
- "bingSiteVerification": "",
- "pinterestSiteVerification": "",
- "sameAsLinks": {
- "twitter": {
- "siteName": "Twitter",
- "handle": "twitter",
- "url": ""
- },
- "facebook": {
- "siteName": "Facebook",
- "handle": "facebook",
- "url": ""
- },
- "wikipedia": {
- "siteName": "Wikipedia",
- "handle": "wikipedia",
- "url": ""
- },
- "linkedin": {
- "siteName": "LinkedIn",
- "handle": "linkedin",
- "url": ""
- },
- "googleplus": {
- "siteName": "Google+",
- "handle": "googleplus",
- "url": ""
- },
- "youtube": {
- "siteName": "YouTube",
- "handle": "youtube",
- "url": ""
- },
- "instagram": {
- "siteName": "Instagram",
- "handle": "instagram",
- "url": ""
- },
- "pinterest": {
- "siteName": "Pinterest",
- "handle": "pinterest",
- "url": ""
- },
- "github": {
- "siteName": "GitHub",
- "handle": "github",
- "url": ""
- },
- "vimeo": {
- "siteName": "Vimeo",
- "handle": "vimeo",
- "url": ""
- }
+ {
+ "open": null,
+ "close": null
},
- "siteLinksSearchTarget": "",
- "siteLinksQueryInput": "",
- "referrer": "no-referrer-when-downgrade",
- "additionalSitemapUrls": [],
- "additionalSitemapUrlsDateUpdated": null,
- "additionalSitemaps": []
- },
- "FrontendTemplateContainer": [
{
- "humans": "/* TEAM */\n\nCreator: nystudio107\nURL: https://nystudio107.com/\nDescription: We do technology-based consulting, branding, design, and development. Making the web better one site at a time, with a focus on performance, usability & SEO\n\n/* THANKS */\n\nCraft CMS - https://craftcms.com\nPixel & Tonic - https://pixelandtonic.com\n\n/* SITE */\n\nStandards: HTML5, CSS3\nComponents: Craft CMS 3, Yii2, PHP, JavaScript, SEOmatic\n"
+ "open": null,
+ "close": null
},
{
- "robots": "# robots.txt for http://localhost:8000/\n\nsitemap: http://localhost:8000/sitemaps-1-sitemap.xml\nsitemap: http://localhost:8000/es/sitemaps-1-sitemap.xml\n\n# local - disallow all\n\nUser-agent: *\nDisallow: /\n\n"
+ "open": null,
+ "close": null
},
{
- "ads": "# ads.txt file for http://localhost:8000/\n# More info: https://support.google.com/admanager/answer/7441288?hl=en\nhttp://localhost:8000/,123,DIRECT\n"
+ "open": null,
+ "close": null
+ },
+ {
+ "open": null,
+ "close": null
}
- ]
+ ],
+ "restaurantServesCuisine": "",
+ "restaurantMenuUrl": "",
+ "restaurantReservationsUrl": ""
+ },
+ "twitterHandle": "",
+ "facebookProfileId": "",
+ "facebookAppId": "",
+ "googleSiteVerification": "",
+ "bingSiteVerification": "",
+ "pinterestSiteVerification": "",
+ "sameAsLinks": {
+ "twitter": {
+ "siteName": "Twitter",
+ "handle": "twitter",
+ "url": ""
+ },
+ "facebook": {
+ "siteName": "Facebook",
+ "handle": "facebook",
+ "url": ""
+ },
+ "wikipedia": {
+ "siteName": "Wikipedia",
+ "handle": "wikipedia",
+ "url": ""
+ },
+ "linkedin": {
+ "siteName": "LinkedIn",
+ "handle": "linkedin",
+ "url": ""
+ },
+ "googleplus": {
+ "siteName": "Google+",
+ "handle": "googleplus",
+ "url": ""
+ },
+ "youtube": {
+ "siteName": "YouTube",
+ "handle": "youtube",
+ "url": ""
+ },
+ "instagram": {
+ "siteName": "Instagram",
+ "handle": "instagram",
+ "url": ""
+ },
+ "pinterest": {
+ "siteName": "Pinterest",
+ "handle": "pinterest",
+ "url": ""
+ },
+ "github": {
+ "siteName": "GitHub",
+ "handle": "github",
+ "url": ""
+ },
+ "vimeo": {
+ "siteName": "Vimeo",
+ "handle": "vimeo",
+ "url": ""
+ }
+ },
+ "siteLinksSearchTarget": "",
+ "siteLinksQueryInput": "",
+ "referrer": "no-referrer-when-downgrade",
+ "additionalSitemapUrls": [],
+ "additionalSitemapUrlsDateUpdated": null,
+ "additionalSitemaps": []
+ },
+ "FrontendTemplateContainer": [
+ {
+ "humans": "/* TEAM */\n\nCreator: nystudio107\nURL: https://nystudio107.com/\nDescription: We do technology-based consulting, branding, design, and development. Making the web better one site at a time, with a focus on performance, usability & SEO\n\n/* THANKS */\n\nCraft CMS - https://craftcms.com\nPixel & Tonic - https://pixelandtonic.com\n\n/* SITE */\n\nStandards: HTML5, CSS3\nComponents: Craft CMS 3, Yii2, PHP, JavaScript, SEOmatic\n"
+ },
+ {
+ "robots": "# robots.txt for http://localhost:8000/\n\nsitemap: http://localhost:8000/sitemaps-1-sitemap.xml\nsitemap: http://localhost:8000/es/sitemaps-1-sitemap.xml\n\n# local - disallow all\n\nUser-agent: *\nDisallow: /\n\n"
+ },
+ {
+ "ads": "# ads.txt file for http://localhost:8000/\n# More info: https://support.google.com/admanager/answer/7441288?hl=en\nhttp://localhost:8000/,123,DIRECT\n"
+ }
+ ]
}
```
+:::
You can also request individual meta containers.
@@ -807,9 +799,10 @@ Title container:
```
...will return just the Title container:
+
```json
{
- "MetaTitleContainer": "
[devMode] Craft3 | Homepage"
+ "MetaTitleContainer": "[devMode] Craft3 | Homepage"
}
```
@@ -820,10 +813,11 @@ Tag container:
```
...will return just the Tag container:
+
```json
{
- "MetaTagContainer": ""
- }
+ "MetaTagContainer": ""
+}
```
Script container:
@@ -835,7 +829,7 @@ Script container:
...will return just the Script container:
```json
{
- "MetaScriptContainer": ""
+ "MetaScriptContainer": ""
}
```
@@ -846,9 +840,10 @@ Link container:
```
...will return just the Link container:
+
```json
{
- "MetaLinkContainer": ""
+ "MetaLinkContainer": ""
}
```
@@ -861,7 +856,7 @@ JSON-LD container:
...will return just the JSON-LD container:
```json
{
- "MetaJsonLdContainer": ""
+ "MetaJsonLdContainer": ""
}
```
@@ -874,7 +869,7 @@ SiteVars container:
...will return just the MetaSiteVars container:
```json
{
- "MetaSiteVarsContainer": "{\"siteName\":\"woof\",\"identity\":{\"siteType\":\"Organization\",\"siteSubType\":\"LocalBusiness\",\"siteSpecificType\":\"none\",\"computedType\":\"LocalBusiness\",\"genericName\":\"\",\"genericAlternateName\":\"\",\"genericDescription\":\"\",\"genericUrl\":\"$HOME\",\"genericImage\":null,\"genericImageWidth\":\"229\",\"genericImageHeight\":\"220\",\"genericImageIds\":[\"25\"],\"genericTelephone\":\"\",\"genericEmail\":\"\",\"genericStreetAddress\":\"\",\"genericAddressLocality\":\"\",\"genericAddressRegion\":\"\",\"genericPostalCode\":\"\",\"genericAddressCountry\":\"\",\"genericGeoLatitude\":\"\",\"genericGeoLongitude\":\"\",\"personGender\":\"Male\",\"personBirthPlace\":\"\",\"organizationDuns\":\"\",\"organizationFounder\":\"\",\"organizationFoundingDate\":\"\",\"organizationFoundingLocation\":\"\",\"organizationContactPoints\":\"\",\"corporationTickerSymbol\":\"\",\"localBusinessPriceRange\":\"$\",\"localBusinessOpeningHours\":[{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null}],\"restaurantServesCuisine\":\"\",\"restaurantMenuUrl\":\"\",\"restaurantReservationsUrl\":\"\"},\"creator\":{\"siteType\":\"Organization\",\"siteSubType\":\"LocalBusiness\",\"siteSpecificType\":\"none\",\"computedType\":\"LocalBusiness\",\"genericName\":\"\",\"genericAlternateName\":\"\",\"genericDescription\":\"\",\"genericUrl\":\"\",\"genericImage\":null,\"genericImageWidth\":\"1340\",\"genericImageHeight\":\"596\",\"genericImageIds\":[\"24\"],\"genericTelephone\":\"\",\"genericEmail\":\"\",\"genericStreetAddress\":\"\",\"genericAddressLocality\":\"\",\"genericAddressRegion\":\"\",\"genericPostalCode\":\"\",\"genericAddressCountry\":\"\",\"genericGeoLatitude\":\"\",\"genericGeoLongitude\":\"\",\"personGender\":\"Male\",\"personBirthPlace\":\"\",\"organizationDuns\":\"\",\"organizationFounder\":\"\",\"organizationFoundingDate\":\"\",\"organizationFoundingLocation\":\"\",\"organizationContactPoints\":\"\",\"corporationTickerSymbol\":\"\",\"localBusinessPriceRange\":\"$\",\"localBusinessOpeningHours\":[{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null}],\"restaurantServesCuisine\":\"\",\"restaurantMenuUrl\":\"\",\"restaurantReservationsUrl\":\"\"},\"twitterHandle\":\"\",\"facebookProfileId\":\"\",\"facebookAppId\":\"\",\"googleSiteVerification\":\"\",\"bingSiteVerification\":\"\",\"pinterestSiteVerification\":\"\",\"sameAsLinks\":{\"twitter\":{\"siteName\":\"Twitter\",\"handle\":\"twitter\",\"url\":\"\"},\"facebook\":{\"siteName\":\"Facebook\",\"handle\":\"facebook\",\"url\":\"\"},\"wikipedia\":{\"siteName\":\"Wikipedia\",\"handle\":\"wikipedia\",\"url\":\"\"},\"linkedin\":{\"siteName\":\"LinkedIn\",\"handle\":\"linkedin\",\"url\":\"\"},\"googleplus\":{\"siteName\":\"Google+\",\"handle\":\"googleplus\",\"url\":\"\"},\"youtube\":{\"siteName\":\"YouTube\",\"handle\":\"youtube\",\"url\":\"\"},\"instagram\":{\"siteName\":\"Instagram\",\"handle\":\"instagram\",\"url\":\"\"},\"pinterest\":{\"siteName\":\"Pinterest\",\"handle\":\"pinterest\",\"url\":\"\"},\"github\":{\"siteName\":\"GitHub\",\"handle\":\"github\",\"url\":\"\"},\"vimeo\":{\"siteName\":\"Vimeo\",\"handle\":\"vimeo\",\"url\":\"\"}},\"siteLinksSearchTarget\":\"\",\"siteLinksQueryInput\":\"\",\"referrer\":\"no-referrer-when-downgrade\",\"additionalSitemapUrls\":[],\"additionalSitemapUrlsDateUpdated\":null,\"additionalSitemaps\":[]}"
+ "MetaSiteVarsContainer": "{\"siteName\":\"woof\",\"identity\":{\"siteType\":\"Organization\",\"siteSubType\":\"LocalBusiness\",\"siteSpecificType\":\"none\",\"computedType\":\"LocalBusiness\",\"genericName\":\"\",\"genericAlternateName\":\"\",\"genericDescription\":\"\",\"genericUrl\":\"$HOME\",\"genericImage\":null,\"genericImageWidth\":\"229\",\"genericImageHeight\":\"220\",\"genericImageIds\":[\"25\"],\"genericTelephone\":\"\",\"genericEmail\":\"\",\"genericStreetAddress\":\"\",\"genericAddressLocality\":\"\",\"genericAddressRegion\":\"\",\"genericPostalCode\":\"\",\"genericAddressCountry\":\"\",\"genericGeoLatitude\":\"\",\"genericGeoLongitude\":\"\",\"personGender\":\"Male\",\"personBirthPlace\":\"\",\"organizationDuns\":\"\",\"organizationFounder\":\"\",\"organizationFoundingDate\":\"\",\"organizationFoundingLocation\":\"\",\"organizationContactPoints\":\"\",\"corporationTickerSymbol\":\"\",\"localBusinessPriceRange\":\"$\",\"localBusinessOpeningHours\":[{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null}],\"restaurantServesCuisine\":\"\",\"restaurantMenuUrl\":\"\",\"restaurantReservationsUrl\":\"\"},\"creator\":{\"siteType\":\"Organization\",\"siteSubType\":\"LocalBusiness\",\"siteSpecificType\":\"none\",\"computedType\":\"LocalBusiness\",\"genericName\":\"\",\"genericAlternateName\":\"\",\"genericDescription\":\"\",\"genericUrl\":\"\",\"genericImage\":null,\"genericImageWidth\":\"1340\",\"genericImageHeight\":\"596\",\"genericImageIds\":[\"24\"],\"genericTelephone\":\"\",\"genericEmail\":\"\",\"genericStreetAddress\":\"\",\"genericAddressLocality\":\"\",\"genericAddressRegion\":\"\",\"genericPostalCode\":\"\",\"genericAddressCountry\":\"\",\"genericGeoLatitude\":\"\",\"genericGeoLongitude\":\"\",\"personGender\":\"Male\",\"personBirthPlace\":\"\",\"organizationDuns\":\"\",\"organizationFounder\":\"\",\"organizationFoundingDate\":\"\",\"organizationFoundingLocation\":\"\",\"organizationContactPoints\":\"\",\"corporationTickerSymbol\":\"\",\"localBusinessPriceRange\":\"$\",\"localBusinessOpeningHours\":[{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null},{\"open\":null,\"close\":null}],\"restaurantServesCuisine\":\"\",\"restaurantMenuUrl\":\"\",\"restaurantReservationsUrl\":\"\"},\"twitterHandle\":\"\",\"facebookProfileId\":\"\",\"facebookAppId\":\"\",\"googleSiteVerification\":\"\",\"bingSiteVerification\":\"\",\"pinterestSiteVerification\":\"\",\"sameAsLinks\":{\"twitter\":{\"siteName\":\"Twitter\",\"handle\":\"twitter\",\"url\":\"\"},\"facebook\":{\"siteName\":\"Facebook\",\"handle\":\"facebook\",\"url\":\"\"},\"wikipedia\":{\"siteName\":\"Wikipedia\",\"handle\":\"wikipedia\",\"url\":\"\"},\"linkedin\":{\"siteName\":\"LinkedIn\",\"handle\":\"linkedin\",\"url\":\"\"},\"googleplus\":{\"siteName\":\"Google+\",\"handle\":\"googleplus\",\"url\":\"\"},\"youtube\":{\"siteName\":\"YouTube\",\"handle\":\"youtube\",\"url\":\"\"},\"instagram\":{\"siteName\":\"Instagram\",\"handle\":\"instagram\",\"url\":\"\"},\"pinterest\":{\"siteName\":\"Pinterest\",\"handle\":\"pinterest\",\"url\":\"\"},\"github\":{\"siteName\":\"GitHub\",\"handle\":\"github\",\"url\":\"\"},\"vimeo\":{\"siteName\":\"Vimeo\",\"handle\":\"vimeo\",\"url\":\"\"}},\"siteLinksSearchTarget\":\"\",\"siteLinksQueryInput\":\"\",\"referrer\":\"no-referrer-when-downgrade\",\"additionalSitemapUrls\":[],\"additionalSitemapUrlsDateUpdated\":null,\"additionalSitemaps\":[]}"
}
```
@@ -885,17 +880,20 @@ Frontend Templates container:
```
...will return just the Frontend Templates container:
+
```json
{
- "FrontendTemplateContainer": "[{\"humans\":\"/* TEAM */\\n\\nCreator: nystudio107\\nURL: https://nystudio107.com/\\nDescription: We do technology-based consulting, branding, design, and development. Making the web better one site at a time, with a focus on performance, usability & SEO\\n\\n/* THANKS */\\n\\nCraft CMS - https://craftcms.com\\nPixel & Tonic - https://pixelandtonic.com\\n\\n/* SITE */\\n\\nStandards: HTML5, CSS3\\nComponents: Craft CMS 3, Yii2, PHP, JavaScript, SEOmatic\\n\"},{\"robots\":\"# robots.txt for http://localhost:8000/\\n\\nsitemap: http://localhost:8000/sitemaps-1-sitemap.xml\\nsitemap: http://localhost:8000/es/sitemaps-1-sitemap.xml\\n\\n# local - disallow all\\n\\nUser-agent: *\\nDisallow: /\\n\\n\"},{\"ads\":\"# ads.txt file for http://localhost:8000/\\n# More info: https://support.google.com/admanager/answer/7441288?hl=en\\nhttp://localhost:8000/,123,DIRECT\\n\"}]"
+ "FrontendTemplateContainer": "[{\"humans\":\"/* TEAM */\\n\\nCreator: nystudio107\\nURL: https://nystudio107.com/\\nDescription: We do technology-based consulting, branding, design, and development. Making the web better one site at a time, with a focus on performance, usability & SEO\\n\\n/* THANKS */\\n\\nCraft CMS - https://craftcms.com\\nPixel & Tonic - https://pixelandtonic.com\\n\\n/* SITE */\\n\\nStandards: HTML5, CSS3\\nComponents: Craft CMS 3, Yii2, PHP, JavaScript, SEOmatic\\n\"},{\"robots\":\"# robots.txt for http://localhost:8000/\\n\\nsitemap: http://localhost:8000/sitemaps-1-sitemap.xml\\nsitemap: http://localhost:8000/es/sitemaps-1-sitemap.xml\\n\\n# local - disallow all\\n\\nUser-agent: *\\nDisallow: /\\n\\n\"},{\"ads\":\"# ads.txt file for http://localhost:8000/\\n# More info: https://support.google.com/admanager/answer/7441288?hl=en\\nhttp://localhost:8000/,123,DIRECT\\n\"}]"
}
```
All of the individual container controller API endpoints also accept the `&asArray=true` parameter if you’d like the data in array form.
-
+
### Schema.org API Endpoints
-**N.B.:** Anonymous access to the Schema.org JSON-LD endpoints are disabled by default; you’ll need to enable them in SEOmatic → Plugin Settings → Endpoints
+::: tip
+Anonymous access to the Schema.org JSON-LD endpoints are disabled by default; enable them in **SEOmatic** → **Plugin Settings** → **Endpoints**.
+:::
To get a key-value array of a given [Schema.org](http://schema.org/docs/full.html) type:
@@ -920,7 +918,8 @@ You can narrow this down to a specific sub-type list by passing in a `path` of s
/actions/seomatic/json-ld/get-type-array?path=CreativeWork.Article
```
...this would output all of the sub-types of `Article`:
-```
+
+```json
{
"AdvertiserContentArticle": "AdvertiserContentArticle",
"NewsArticle": {
@@ -946,5 +945,3 @@ You can narrow this down to a specific sub-type list by passing in a `path` of s
}
}
```
-
-Brought to you by [nystudio107](https://nystudio107.com/)
diff --git a/docs/docs/configuring.md b/docs/docs/configuring.md
deleted file mode 100644
index 3cb3dc05c..000000000
--- a/docs/docs/configuring.md
+++ /dev/null
@@ -1,622 +0,0 @@
----
-title: Configuring SEOmatic
-description: Configuring SEOmatic documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
----
-# Configuring SEOmatic
-
-As soon as you install SEOmatic, it automatically will render metadata on your web pages, and create sitemaps for all of your Sections, Category Groups, and Commerce Product Types that have public URLs. You don’t need to add any template code for this to happen.
-
-![Screenshot](./resources/screenshots/seomatic-multi-site.png)
-
-All of SEOmatic’s settings are multi-site aware, allowing you to have different settings for each site/language combination.
-
-For SEOmatic to be truly useful, you need to configure it so that it knows where to _pull_ SEO content from.
-
-**N.B.** Please ensure that you set up your [Multi-Environment Config Settings](#multi-environment-config-settings) if you will be using SEOmatic across multiple environments.
-
-## Dashboard
-
-![Screenshot](./resources/screenshots/seomatic-dashboard.png)
-
-The Dashboard gives you an overview of how fully set up your SEO setting in SEOmatic are, for Global SEO, Content SEO, and Site Settings.
-
-Click on any of the graphs to jump to the section in question to fill things out in more detail.
-
-## Global SEO
-
-**Global SEO** is where you set all of the default site-wide settings. The **Copy Settings From:** dropdown allows you to easily copy settings from one site to another.
-
-SEOmatic allows you to have different Global SEO settings on a per-site basis.
-
-### General
-
-![Screenshot](./resources/screenshots/seomatic-global-general.png)
-
-Best practices for modern SEO are for the meta information to _reflect your content_, so you should set up the fields that SEOmatic _pulls_ the **SEO Title**, **SEO Description**, and **SEO Image** from.
-
-### Twitter
-
-![Screenshot](./resources/screenshots/seomatic-global-twitter.png)
-
-By default, the Twitter and Facebook settings will mirror what you set in the **General** section, but you can customize them to your heart’s content.
-
-### Facebook
-
-![Screenshot](./resources/screenshots/seomatic-global-facebook.png)
-
-By default, the Twitter and Facebook settings will mirror what you set in the **General** section, but you can customize them to your heart’s content.
-
-### Robots
-
-![Screenshot](./resources/screenshots/seomatic-global-robots.png)
-
-A `robots.txt` file is a file at the root of your site that indicates those parts of your site you don’t want accessed by search engine crawlers. The file uses the [Robots Exclusion Standard](http://www.robotstxt.org/robotstxt.html), which is a protocol with a small set of commands that can be used to indicate access to your site by section and by specific kinds of web crawlers (such as mobile crawlers vs desktop crawlers).
-
-You shouldn’t need to edit the default `robots.txt` Template, but you can if you like.
-
-SEOmatic automatically handles requests for `/robots.txt`. For this to work, make sure that you do not have an actual `robots.txt` file in your `web/` folder (because that will take precedence).
-
-If you are running Nginx, make sure that you don’t have a line like:
-
- location = /robots.txt { access_log off; log_not_found off; }
-
-...in your config file. A directive like this will prevent SEOmatic from being able to service the request for `/robots.txt`. If you do have a line like this in your config file, just comment it out, and restart Nginx with `sudo nginx -s reload`.
-
-The **View robots.txt** button lets you view your rendered `robots.txt`.
-
-### Humans
-
-![Screenshot](./resources/screenshots/seomatic-global-humans.png)
-
-[Humans.txt](http://humanstxt.org/) is an initiative for knowing the people behind a site. It’s a text file that contains information about the different people who have contributed to building the site. By adding a text file, you can prove your authorship (not your property) in an external, fast, easy and accessible way.
-
-Feel free to edit the default `humans.txt` Template to your heart’s content.
-
-The **View humans.txt** button lets you view your rendered `humans.txt`.
-
-### Ads
-
-![Screenshot](./resources/screenshots/seomatic-global-ads.png)
-
-The [ads.txt](https://iabtechlab.com/ads-txt/) project is simple: Increase transparency in the programmatic advertising ecosystem. Ads.txt stands for Authorized Digital Sellers and is a simple, flexible and secure method that publishers and distributors can use to publicly declare the companies they authorize to sell their digital inventory.
-
-Feel free to edit the default `ads.txt` Template to your heart’s content.
-
-The **View ads.txt** button lets you view your rendered `ads.txt`.
-
-### Security
-
-![Screenshot](./resources/screenshots/seomatic-global-security.png)
-
-The [security.txt](https://securitytxt.org/) defines a standard to help organizations define the process for security researchers to disclose security vulnerabilities securely
-
-Feel free to edit the default `security.txt` Template to your heart’s content.
-
-The **View security.txt** button lets you view your rendered `security.txt`.
-
-### Global SEO Control Panel Fields
-
-The fields in the Control Panel Global SEO settings are parsed as Twig object templates, so in addition to plain old text, you can also put single and double bracket Twig expressions.
-
-SEOmatic fields are also parsed for aliases, and in Craft 3.1, for [environment variables](https://docs.craftcms.com/v3/config/environments.html#control-panel-settings) as well.
-
-This is entirely optional; in typical usage the controls you have in the Control Panel for pulling from other fields will be all you need. But the ability is there if you need it.
-
-For example, the following will output the contents of the **companyInfo** field from the **siteInfo** Global:
-
-```twig
-{{ siteInfo.companyInfo }}
-```
-
-You can even do complex expressions, such as the following which outputs the first field that isn’t empty, or a default text:
-
-```twig
-{{ siteInfo.companyInfo ??? siteInfo.companySummary ??? "Some default text" }}
-```
-
-The above uses the `???` empty coalesce operator that comes with SEOmatic; check out [SEOmatic’s ??? Empty Coalesce operator](#seomatics--empty-coalesce-operator) for details.
-
-You can also access SEOmatic global variables (discussed below):
-
-```twig
-{seomatic.meta.seoTitle}
-```
-Normal Twig double bracket syntax is supported too:
-
-```twig
-{{ seomatic.meta.seoTitle }}
-```
-The single bracket syntax is just a shortcut, and provided for backwards compatibility with previous versions of SEOmatic.
-
-## Content SEO
-
-![Screenshot](./resources/screenshots/seomatic-content.png)
-
-**Content SEO** is where you can configure each Section, Category Group and Commerce Product Type that has public URLs. You’ll see a list of all of your Sections, Category Groups, and Commerce Product Types that have public URLs, with status indicators letting you know what has been configured for each.
-
-SEOmatic allows you to have different Content SEO settings on a per-site basis, and also on a per-[Entry Type](https://docs.craftcms.com/v3/sections-and-entries.html#entry-types) basis.
-
-Click on a Section, Category Group, or Commerce Product Type name to edit its settings.
-
-### General
-
-![Screenshot](./resources/screenshots/seomatic-content-general.png)
-
-Best practices for modern SEO are for the meta information to _reflect your content_, so you should set up the fields that SEOmatic _pulls_ the **SEO Title**, **SEO Description**, and **SEO Image** from.
-
-### Twitter
-
-![Screenshot](./resources/screenshots/seomatic-content-twitter.png)
-
-By default, the Twitter and Facebook settings will mirror what you set in the **General** section, but you can customize them to your heart’s content.
-
-### Facebook
-
-![Screenshot](./resources/screenshots/seomatic-content-facebook.png)
-
-By default, the Twitter and Facebook settings will mirror what you set in the **General** section, but you can customize them to your heart’s content.
-
-### Sitemap
-
-![Screenshot](./resources/screenshots/seomatic-content-sitemap.png)
-
-SEOmatic automatically creates a sitemap index for each of your Site Groups. This sitemap index points to individual sitemaps for each of your Sections, Category Groups, and Commerce Product Types.
-
-Instead of one massive sitemap that must be updated any time anything changes, only the sitemap for the Section, Category Group, or Commerce Product Type will be updated when something changes in it.
-
-SEOmatic can automatically include files such as `.pdf`, `.xls`, `.doc` and other indexable file types in Asset fields or Asset fields in matrix or Neo blocks.
-
-In addition, SEOmatic can automatically create [Image sitemaps](https://support.google.com/webmasters/answer/178636?hl=en) and [Video sitemaps](https://developers.google.com/webmasters/videosearch/sitemaps) from images & videos in Asset fields or Asset fields in matrix or Neo blocks
-
-Sitemap Indexes are automatically submitted to search engines whenever a new Section, Category Group, or Commerce Product Type is added.
-
-Section Sitemaps are automatically submitted to search engines whenever a new Element in that Section, Category Group, or Commerce Product Type is added.
-
-#### Sitemap Generation
-
-Because XML sitemaps can be quite time-intensive to generate as the number of entries scales up, SEOmatic creates your sitemaps via a Queue job, and caches the result. The cache is automatically broken whenever something in that sitemap is changed, and a new Queue job is created to regenerate it.
-
-If `runQueueAutomatically` is set to `false` in [General Config Settings](https://docs.craftcms.com/v3/config/config-settings.html#runqueueautomatically) the Queue job to create the sitemap will not be run during the http request for the sitemap. You’ll need to run it manually via whatever means you use to run the Queue.
-
-Normally SEOmatic will regenerate the sitemap for a Section, Category Group, or Product any time you save an element. However, if you are importing a large number of elements, or prefer to regenerate the sitemap manually you can set disable the **Regenerate Sitemaps Automatically** option in SEOmatic’s Plugin Settings.
-
-![Screenshot](./resources/screenshots/seomatic-sitemap-console-command.png)
-
-You can then regenerate the sitemap via CLI. This will regenerate all sitemaps:
-
-```bash
-./craft seomatic/sitemap/generate
-```
-
-You can also limit it to a specific Section, Category Group, or Product handle:
-
-```bash
-./craft seomatic/sitemap/generate --handle=blog
-```
-
-...or you can regenerate all sitemaps for a specific `siteId`:
-
-```bash
-./craft seomatic/sitemap/generate --siteId=1
-```
-
-...or both:
-
-```bash
-./craft seomatic/sitemap/generate --handle=blog --siteId=1
-```
-**N.B.:** If you do disable **Regenerate Sitemaps Automatically** sitemaps will _not_ be updated unless you do so manually via the CLI, or clear SEOmatic’s sitemap caches via Utilities->Clear Caches.
-
-#### Additional Sitemaps
-
-If you have custom sitemaps that are not in the CMS, you can manually add them to their own Sitemap Index via **Site Settings** → **Sitemap**.
-
-You can also add to it via a plugin:
-
-```php
-use nystudio107\seomatic\events\RegisterSitemapsEvent;
-use nystudio107\seomatic\models\SitemapIndexTemplate;
-use yii\base\Event;
-Event::on(SitemapIndexTemplate::class, SitemapIndexTemplate::EVENT_REGISTER_SITEMAPS, function(RegisterSitemapsEvent $e) {
- $e->sitemaps[] = [
- 'loc' => $url,
- 'lastmod' => $lastMod,
- ];
-});
-```
-
-#### Additional Sitemap URLs
-
-If you have custom URLs that are not in the CMS, you can manually add them to their own Sitemap Index via **Site Settings** → **Sitemap**.
-
-You can also add to it via a plugin:
-
-```php
-use nystudio107\seomatic\events\RegisterSitemapUrlsEvent;
-use nystudio107\seomatic\models\SitemapCustomTemplate;
-use yii\base\Event;
-Event::on(SitemapCustomTemplate::class, SitemapCustomTemplate::EVENT_REGISTER_SITEMAP_URLS, function(RegisterSitemapUrlsEvent $e) {
- $e->sitemaps[] = [
- 'loc' => $url,
- 'changefreq' => $changeFreq,
- 'priority' => $priority,
- 'lastmod' => $lastMod,
- ];
- });
-```
-
-### Content SEO Control Panel Fields
-
-The fields in the Control Panel Content SEO settings are parsed as Twig object templates, so in addition to plain old text, you can also put single and double bracket Twig expressions.
-
-SEOmatic fields are also parsed for aliases, and in Craft 3.1, for [environment variables](https://docs.craftcms.com/v3/config/environments.html#control-panel-settings) as well.
-
-This is entirely optional; in typical usage the controls you have in the Control Panel for pulling from other fields will be all you need. But the ability is there if you need it.
-
-For example, the following will output the contents of the **description** field from the current **Entry**:
-
-```twig
-{entry.description}
-```
-
-Normal Twig double bracket syntax is supported too:
-
-```twig
-{{ entry.description }}
-```
-The single bracket syntax is just a shortcut, and provided for backwards compatibility with previous versions of SEOmatic.
-
-The same applies to any SEOmatic global variables (discussed below):
-
-```twig
-{seomatic.meta.seoTitle}
-```
-Is the same as:
-
-```twig
-{{ seomatic.meta.seoTitle }}
-```
-
-You can even do complex expressions, such as the following which outputs the first field that isn’t empty, or a default text:
-
-```twig
-{{ entry.description ??? entry.summary ??? "Some default text" }}
-```
-
-The above uses the `???` empty coalesce operator that comes with SEOmatic; check out [SEOmatic’s ??? Empty Coalesce operator](#seomatics--empty-coalesce-operator) for details.
-
-## Site Settings
-
-### Identity
-
-![Screenshot](./resources/screenshots/seomatic-site-identity.png)
-
-These Site Identity settings are used to globally define the identity and ownership of the site.
-
-They are used in combination with the SEO Template Meta settings to generate [JSON-LD](https://developers.google.com/schemas/formats/json-ld?hl=en) microdata.
-
-The Site Owner type determines the JSON-LD schema that will be used to identity the site to search engines.
-
-Leave any fields blank that aren’t applicable or which you do not want as part of the SEO schema.
-
-### Creator
-
-![Screenshot](./resources/screenshots/seomatic-site-creator.png)
-
-These Site Creator settings are used to globally define the _creator_ (such as the agency or freelancer) of the site.
-
-They are used in combination with the SEO Template Meta settings to generate [JSON-LD](https://developers.google.com/schemas/formats/json-ld?hl=en) microdata as well as the `humans.txt` file.
-
-The Site Creator type determines the JSON-LD schema that will be used to identity the site to search engines.
-
-Leave any fields blank that aren’t applicable or which you do not want as part of the SEO schema.
-
-### Social Media
-
-![Screenshot](./resources/screenshots/seomatic-site-social.png)
-
-The social media settings connect your site to its other points of pressence on the internet. They also facilitate attaching your branding to social media posts via Twitter Cards and Facebook OpenGraph.
-
-### Sitemap
-
-![Screenshot](./resources/screenshots/seomatic-site-sitemap.png)
-
-SEOmatic will automatically create a sitemap for each of your sections, but if you have additional sitemaps or individual URLs that are outside of the CMS that you want to include, you can add them here.
-
-### Miscellaneous
-
-![Screenshot](./resources/screenshots/seomatic-site-misc.png)
-
-Miscellaneous site-wide SEO settings.
-
-## Tracking Scripts
-
-None of the Tracking Scripts are included on the page unless the SEOmatic environment is set to `live` production. If `devMode` is enabled, the SEOmatic environment is automatically set to `local` development.
-
-### Google Analytics
-
-![Screenshot](./resources/screenshots/seomatic-tracking-ga.png)
-
-Google Analytics gives you the digital analytics tools you need to analyze data from all touchpoints in one place, for a deeper understanding of the customer experience. You can then share the insights that matter with your whole organization. [Learn More](https://www.google.com/analytics/analytics/#?modal_active=none)
-
-To include the Google Analytics script despite `devMode` being enabled, you can do:
-
-```twig
-{% do seomatic.script.get('googleAnalytics').include(true) %}
-```
-
-### Google `gtag.js`
-
-![Screenshot](./resources/screenshots/seomatic-tracking-gtag.png)
-
-The global site tag (gtag.js) is a JavaScript tagging framework and API that allows you to send event data to AdWords, DoubleClick, and Google Analytics. Instead of having to manage multiple tags for different products, you can use gtag.js and more easily benefit from the latest tracking features and integrations as they become available. [Learn More](https://developers.google.com/gtagjs/)
-
-To include the gtag script despite `devMode` being enabled, you can do:
-
-```twig
-{% do seomatic.script.get('gtag').include(true) %}
-```
-
-### Google Tag Manager
-
-![Screenshot](./resources/screenshots/seomatic-tracking-gtm.png)
-
-Google Tag Manager is a tag management system that allows you to quickly and easily update tags and code snippets on your site. Once the Tag Manager snippet has been added to your site or mobile app, you can configure tags via a web-based user interface without having to alter and deploy additional code. [Learn More](https://support.google.com/tagmanager/answer/6102821?hl=en)
-
-You can set the `dataLayer` passed in to Google Tag Manager via Twig:
-
-```twig
-{% do seomatic.script.get('googleTagManager').dataLayer({
- 'woof': 'bark'
-}) %}
-```
-
-To include the Google Tag Manager script despite `devMode` being enabled, you can do:
-
-```twig
-{% do seomatic.script.get('googleTagManager').include(true) %}
-```
-
-### Facebook Pixel
-
-![Screenshot](./resources/screenshots/seomatic-tracking-fb.png)
-
-The Facebook pixel is an analytics tool that helps you measure the effectiveness of your advertising. You can use the Facebook pixel to understand the actions people are taking on your site and reach audiences you care about. [Learn More](https://www.facebook.com/business/help/651294705016616)
-
-To include the Facebook Pixel script despite `devMode` being enabled, you can do:
-
-```twig
-{% do seomatic.script.get('facebookPixel').include(true) %}
-```
-
-### LinkedIn Insight
-
-![Screenshot](./resources/screenshots/seomatic-tracking-li.png)
-
-The LinkedIn Insight Tag is a lightweight JavaScript tag that powers conversion tracking, retargeting, and web analytics for LinkedIn ad campaigns.
-
-To include the LinkedIn Insight script despite `devMode` being enabled, you can do:
-
-```twig
-{% do seomatic.script.get('linkedInInsight').include(true) %}
-```
-
-### HubSpot
-
-![Screenshot](./resources/screenshots/seomatic-tracking-hs.png)
-
-If you’re not hosting your entire site on HubSpot, or have pages on your site that are not hosted on HubSpot, you’ll need to install the HubSpot tracking code on your non-HubSpot pages to capture those analytics.
-
-To include the HubSpot script despite `devMode` being enabled, you can do:
-
-```twig
-{% do seomatic.script.get('hubSpot').include(true) %}
-```
-
-## Plugin Settings
-
-![Screenshot](./resources/screenshots/seomatic-plugin-settings.png)
-
-The Plugin Settings lets you control various SEOmatic settings globally (across all sites/languages).
-
-### General Plugin Settings
-
-* **Plugin name** - This is the name that will be used for the plugin everywhere it is referenced in the Control Panel GUI
-* **Automatic Render Enabled** - Controls whether SEOmatic will automatically render metadata on your pages. If you turn this off, you will need to manually render the metadata via `seomatic.tag.render()`, `seomatic.link.render()`, etc. You can selectively disable rendering via Twig with `{% do seomatic.config.renderEnabled(false)` %}
-* **Sitemaps Enabled** - Controls whether SEOmatic will automatically render frontend sitemaps for your site.
-* **Regenerate Sitemaps Automatically** - Controls whether sitemaps will automatically be regenerated when entries are saved.
-* **Submit Sitemap Changes** - Should sitemaps be submitted to search engines automatically whenever there are changes?
-* **Include Homepage in Breadcrumbs** - Should the homepage be included in the generated Breadcrumbs JSON-LD?
-* **Manually Set SEOmatic Environment** - If off, SEOmatic will automatically attempt to determine the current environment. Turn this on to manually set the environment.
-* **Environment** - The server environment, either `live`, `staging`, or `local`. If `devMode` is on, SEOmatic will override this setting to local Development. This setting controls whether certain things render; for instance only in the `live` production environment will Google Analytics and other tracking tags send analytics data. SEOmatic also automatically sets the `robots` tag to `none` for everything but the `live` production environment.
-
-### Appearance Plugin Settings
-
-* **Display Sidebar SEO Preview** - Controls whether to display the Google, Twitter, and Facebook social media previews in the sidebar on entry. Category, and product pages.
-* **Add Social Media Preview Target** - Controls whether to add the Google, Twitter, Facebook, etc. social media previews as a Preview Target.
-* **SEO Preview Sites** - The social media platforms that should be displayed in the SEO Preview
-
-### Title Plugin Settings
-
-* **devMode `` prefix** - If devMode is on, prefix the `` with this string
-* **Control Panel `` prefix** - Prefix the Control Panel `` with this string
-* **devMode Control Panel `` prefix** - If devMode is on, prefix the Control Panel `` with this string
-* **Separator Character** - The separator character to use for the `` tag
-* **Max SEO Title Length** - The max number of characters in the `` tag; anything beyond this will be truncated on word boundaries
-* **Max SEO Description Length** - The max number of characters in the `meta description` tag
-* **Truncate Title Tags** - Should Title tags be truncated at the max length, on word boundaries?
-* **Truncate Description Tags** - Should Description tags be truncated at the max length, on word boundaries?
-
-### Tags Plugin Settings
-
-* **Add `hreflang` Tags** - Controls whether SEOmatic will automatically add `hreflang` and `og:locale:alternate` tags.
-* **Include `x-default` hreflang Tag** - Controls whether SEOmatic will automatically include an x-default hreflang tag
-* **Include Paginated `hreflang` Tags** - Controls whether SEOmatic will automatically include hreflang tags on paginated pages
-* **Generator Enabled** - Controls whether SEOmatic will include the meta `generator` tag and `X-Powered-By` header
-* **HTTP Headers Enabled** - Controls whether SEOmatic will automatically add `X-Robots-Tag`, `canonical`, & `Referrer-Policy` to the http response headers.
-* **Nonces for `
+
+```
+
+The above uses the `???` empty coalesce operator that comes with SEOmatic; check out [SEOmatic’s ??? Empty Coalesce operator](./using/empty-coalesce-operator.md) for details.
diff --git a/docs/docs/index.md b/docs/docs/index.md
index 11be1bce8..c9b994fbc 100644
--- a/docs/docs/index.md
+++ b/docs/docs/index.md
@@ -2,47 +2,61 @@
title: SEOmatic plugin for Craft CMS 3.x
description: Documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
---
-[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/quality-score.png?b=v3)](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/?branch=v3) [![Code Coverage](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/coverage.png?b=v3)](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/?branch=v3) [![Build Status](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/build.png?b=v3)](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/build-status/v3)
-[![Code Intelligence Status](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/code-intelligence.svg?b=v3)](https://scrutinizer-ci.com/code-intelligence)
-# SEOmatic plugin for Craft CMS 3.x
+# SEOmatic Plugin for Craft CMS 3.x
-SEOmatic facilitates [modern SEO best practices](https://nystudio107.com/blog/modern-seo-snake-oil-vs-substance) & implementation for Craft CMS 3. It is a turnkey SEO system that is comprehensive, powerful, and flexible.
+SEOmatic is a comprehensive, powerful, and flexible turnkey SEO system that facilitates [modern SEO best practices](https://nystudio107.com/blog/modern-seo-snake-oil-vs-substance) & implementation for Craft CMS.
-![Screenshot](./resources/img/plugin-banner.jpg)
+![Plugin banner that reads “Introducing SEOmatic, SEO done right.”](./resources/img/plugin-banner.jpg)
-Related: [SEOmatic for Craft 2.x](https://github.com/nystudio107/seomatic). SEOmatic for Craft CMS 3 is a complete rewrite & re-architecture from scratch.
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/quality-score.png?b=v4)](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/?branch=v4) [![Code Coverage](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/coverage.png?b=v4)](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/?branch=v4) [![Build Status](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/build.png?b=v4)](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/build-status/v4) [![Code Intelligence Status](https://scrutinizer-ci.com/g/nystudio107/craft-seomatic/badges/code-intelligence.svg?b=v4)](https://scrutinizer-ci.com/code-intelligence)
-**Note**: _The license fee for this plugin is $99.00 via the Craft Plugin Store._
+## Key Features
-One SEO-related topic that SEOmatic _does not_ cover is 404 redirects; for that we recommend our [Retour plugin](https://github.com/nystudio107/craft-retour).
+- Healthy SEO by default, tailored to your Craft site’s content model—including Craft Commerce products.
+- Implements HTML tags, JSON-LD microdata, Twitter Card tags, Facebook Open Graph tags, XML sitemaps, robots.txt, humans.txt, and ads.txt.
+- Supports SEO-friendly pagination.
+- Control panel SEO previews for content authors.
+- Custom fields for overriding default SEO values.
+- Visual Configuration overview for helping with project setup.
+- Deep support for Craft features: multi-site, customizable permissions, headless mode, GraphQL, and more.
+- Tools for validating and debugging metadata.
+- Various utilities for managing additional meta tags, text excerpts, and more.
+
+::: tip Use Retour for 404 Redirects
+SEOmatic _does not_ cover is 404 redirects; for that we recommend our [Retour plugin](https://github.com/nystudio107/craft-retour).
+:::
## Used By
-![Screenshot](./resources/img/moz-logo-blue.png)![Screenshot](./resources/img/craft-cms-logo.png)
+
-SEOmatic is the SEO tool that the SEO experts at [Moz.com](https://moz.com/) and the creators of Craft CMS, Pixel & Tonic, rely on to handle their SEO!
+The SEO experts at [Moz.com](https://moz.com/) and the creators of Craft CMS rely on SEOmatic!
## Requirements
-This plugin requires Craft CMS 3.1.19 or later.
+This plugin requires Craft CMS 3.0.0 or later.
## Installation
-To install SEOmatic, follow these steps:
-
1. Open your terminal and go to your Craft project:
- cd /path/to/project
+ ```
+ cd /path/to/project
+ ```
-2. Then tell Composer to load the plugin:
+2. Tell Composer to load the plugin:
- composer require nystudio107/craft-seomatic
+ ```
+ composer require nystudio107/craft-seomatic
+ ```
-3. Install the plugin via `./craft install/plugin seomatic` via the CLI, or in the Control Panel, go to Settings → Plugins and click the “Install” button for SEOmatic.
+3. Install the plugin via CLI:
-You can also install SEOmatic via the **Plugin Store** in the Craft Control Panel.
+ ```
+ php craft install/plugin seomatic
+ ```
-SEOmatic works on Craft 3.x.
+ Or in the control panel, go to **Settings** → **Plugins** and click **Install** for SEOmatic.
-Brought to you by [nystudio107](https://nystudio107.com/)
+You can alternatively install SEOmatic via the **Plugin Store** in the Craft control panel.
diff --git a/docs/docs/issues.md b/docs/docs/issues.md
index 91ef73939..f0096e3ac 100644
--- a/docs/docs/issues.md
+++ b/docs/docs/issues.md
@@ -2,42 +2,48 @@
title: Issues & Upgrading
description: Issues & Upgrading documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
---
+
# Issues & Upgrading
+Where to report issues and notes for upgrading from previous versions.
+
## Issues
-Please report any issues you find to the [SEOmatic Issues](https://github.com/nystudio107/craft-seomatic/issues) page.
+Please report any issues you find to [SEOmatic Issues](https://github.com/nystudio107/craft-seomatic/issues) on GitHub.
## Upgrading from SEOmatic 1.x for Craft CMS 2.x
-If you are upgrading a site from Craft CMS 2.x to Craft CMS 3.x that used the older SEOmatic plugin, here’s what you need to know.
+If you’re upgrading a site from Craft CMS 2.x to 3.x that used the older SEOmatic plugin, here’s what you need to know.
SEOmatic will migrate your old Craft 2.x Field settings & data in the following ways:
-
- * The Content SEO settings for each Section where you had an old SEOmatic Meta FieldType will be migrated for you.
-
+
+* The Content SEO settings for each Section where you had an old SEOmatic Meta FieldType will be migrated for you.
* If you add a new SEO Settings Field to a section that had an old SEOmatic Meta field in it, it will migrate any custom data you had entered on a per-Entry basis
-**Important:** Keep your old Craft 2.x Seomatic_Meta fields intact; don’t delete them or change the Field type to the new SEO Settings field type. Instead, create a new SEO Settings field in the same Section, Category Group, or Commerce Product Type. It will automatically look for and migrate data from the old Seomatic_Meta Field.
+::: warning
+Keep your old Craft 2.x Seomatic_Meta fields intact; don’t delete them or change them to use the new SEO Settings field type. Instead, create a new SEO Settings field in the same Section, Category Group, or Commerce Product Type. It will automatically look for and migrate data from the old Seomatic_Meta Field.
+:::
SEOmatic for Craft CMS 3 is a complete rewrite and re-architecture from scratch of the plugin. This allowed us to take what we learned from SEOmatic 1.x, and rebuild it with a much more robust and extendable architecture.
If feasible, we think the best way to update sites using SEOmatic is to start fresh, and explore how the conceptual changes in the plugin affect how you use it. In most cases, you don’t even need to use an SEOmatic Field, and the setup is cleaner and easier without it! We hope you love it!
-**N.B.:** The Twig templating syntax has changed (but you may not need to use Twig at all with the new version), so give the docs a once-over.
+::: tip Check Your Templates
+The Twig templating syntax has changed. You may not need to use Twig at all with the new version, but consider giving the [Twig Templating](using/) docs a once-over.
+:::
## Importing Data to SEOmatic
It is highly recommended that you set up mappings from existing content to your SEO via the **Content SEO** settings as described above. Usually this obviates the need to import data into SEOmatic, instead _pulling_ it from your content.
-In addition to that, however, if you also have custom SEO data that you need to import, you can import that into an SEO Settings field using the [FeedMe plugin](https://plugins.craftcms.com/feed-me) from Pixel & Tonic.
-
-**N.B.:** The SEO Settings field is intended to be used as a custom override for your Content SEO Settings. In many cases, you won’t need or want an SEO Settings field at all.
+In addition to that, however, if you also have custom SEO data that you need to import, you can import that into an SEO Settings field using Pixel & Tonic’s [Feed Me plugin](https://plugins.craftcms.com/feed-me).
-Once you have added an SEO Settings field added to a Section, it will show up as an import target in FeedMe:
+::: tip
+The SEO Settings field is meant to be a custom override for your Content SEO Settings. In many cases, you won’t need or want an SEO Settings field at all.
+:::
-![Screenshot](./resources/screenshots/seomatic-feedme-import.png)
+Once you have added an SEO Settings field added to a Section, it will show up as an import target in Feed Me:
-See the [FeedMe documentation](https://docs.craftcms.com/feed-me/v4/) for more information on importing data into Craft CMS.
+![Screenshot of Feed Me import fields with a long list of SEO mappings](./resources/screenshots/seomatic-feedme-import.png)
-Brought to you by [nystudio107](https://nystudio107.com/)
+See the [Feed Me documentation](https://docs.craftcms.com/feed-me/v4/) for more information on importing data into Craft CMS.
diff --git a/docs/docs/multi-site.md b/docs/docs/multi-site.md
new file mode 100644
index 000000000..8e3dce9f5
--- /dev/null
+++ b/docs/docs/multi-site.md
@@ -0,0 +1,40 @@
+# Multi-Site Language/Locale Support
+
+SEOmatic comes with multi-site support baked in. Each site has its own localized settings that can be different on a per-site basis.
+
+Craft CMS [defines Sites](https://craftcms.com/docs/3.x/sites.html) as any combination of site settings and locale (language). But there needs to be some way to organize these sites to define a relationship between them. That’s what [Site Groups](https://github.com/craftcms/cms/issues/1668) are for.
+
+SEOmatic treats each Site Group as a separate entity, and any sites contained in that site group are treated as localizations of the same site.
+
+This is necessary because there needs to be some way to let SEOmatic know what the relationship is between the various sites.
+
+So for example, you might have:
+
+```
+├── Primary Site Group
+│ ├── English Site
+│ ├── Chinese Site
+| └── German Site
+├── Sister Site Group
+│ ├── English Site
+| └── German Site
+```
+
+While you technically don’t have to organize your Site Groups in this manner, SEOmatic currently requires it so that it can understand the relationship between your sites.
+
+This is necessary because for a variety of SEO-related things, we need to tell search engines what is really just another localization/translation of the same thing.
+
+If you _don’t_ want to organize your sites in this manner, you’ll need to turn off the **Site Groups define logically separate sites** setting on the Plugin Settings page.
+
+Sites that are grouped together under the same Site Group will have `` & `` URLs added automatically in the HTML.
+
+To disable SEOmatic’s automatic rendering of these tags, you can do:
+
+```twig
+{% do seomatic.link.get('alternate').include(false) %}
+{% do seomatic.tag.get('og:locale:alternate').include(false) %}
+```
+
+Sites that are grouped together under the same Site Group will also be included in the appropriate sitemap indexes, and have `` tags added to the respective sitemaps.
+
+To disable the generation of the `` on a per-Entry basis, you can do this by adding an SEO Settings to the Section/Category Group/Product in question, and turn off **Sitemap Enabled** on a per-entry basis.
diff --git a/docs/docs/overview.md b/docs/docs/overview.md
index 72d17deb5..9123d28e7 100644
--- a/docs/docs/overview.md
+++ b/docs/docs/overview.md
@@ -2,27 +2,24 @@
title: SEOmatic Overview
description: SEOmatic Overview documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3 & 4.
---
-# SEOmatic Overview
-
-SEOmatic facilitates [modern SEO best practices](https://nystudio107.com/blog/modern-seo-snake-oil-vs-substance) & implementation for Craft CMS 3 & 4. It is a turnkey SEO system that is comprehensive, powerful, and flexible.
-SEOmatic allows you to quickly get a site up and running with a robust, comprehensive SEO strategy. It is also implemented in a Craft-y way, in that it is also flexible and customizable.
+# SEOmatic Overview
-It implements [JSON-LD](https://developers.google.com/schemas/formats/json-ld?hl=en) microdata, [Twitter Cards](https://dev.twitter.com/cards/overview) tags, [Facebook OpenGraph](https://developers.facebook.com/docs/sharing/opengraph) tags, [Sitemaps](https://www.sitemaps.org/protocol.html) of your content, [Robots.txt](http://www.robotstxt.org/robotstxt.html) bot directives, [Humans.txt](http://humanstxt.org) authorship accreditation, and as well as HTML meta tags.
+SEOmatic allows you to quickly get a site running with a robust, comprehensive SEO strategy that follows [modern best practices](https://nystudio107.com/blog/modern-seo-snake-oil-vs-substance). It does this in a Craft-y way that’s flexible and customizable.
-SEOmatic populates your templates with SEO Meta in the same way that Craft populates your templates with `entry` variables, with a similar level of freedom and flexibility in terms of how you use them.
+SEOmatic adds meta containers that are available to your templates much like Craft’s `entry` variables. Working with them should feel familiar and flexible.
-SEOmatic works automatically with Craft Commerce 2 as well, providing metadata, JSON-LD structured data, and sitemaps for your Products.
+Unlike Craft’s `entry` variables, the meta containers may use information that’s modified at different levels and expressed in different ways on the site.
-SEOmatic also caches each unique SEO Meta request so that your site performance is minimally impacted by the rich SEO Meta tags provided.
+SEOmatic manages caches behind the scenes to ensure all this information can be used effectively with a minimal impact on site performance.
## The Meta Cascade
-SEOmatic cascades SEO data for any given route, by allowing three distinct places where content authors / admins can add that data:
+SEOmatic cascades SEO data for any given route, by allowing three distinct places where content authors can add that data:
-* **Global SEO** - Global SEO settings are the base settings that are used site-wide. If there are no more specific SEO settings for a given page, it will fall back on the Global SEO settings
-* **Content SEO** - Each Section in Craft CMS (Entries, Categories, Products, etc.) gets its own unique set of SEO settings that will be applied to that section (and Entry Types also can have unique settings). Typically you would set up your Content SEO settings to _pull_ from existing fields in the corresponding sections.
-* **SEO Settings fields** - If you require overrides on a per-entry basis, the SEO Settings field allows you to do that as well. However, if Content SEO is set up to pull from your existing content fields, SEO Settings fields only sparringly need to be used
+1. **Global SEO** – Site-wide base settings applied when there isn’t anything more specific.
+2. **Content SEO** – Settings for each Craft _section_, like Entries, Categories, and Products. Sections and entry types can designate which fields SEOmatic should pull details from.
+3. **SEO Settings Fields** – Entry-level customization via the included SEO Settings field type. Ideally this is only necessary for tailoring when _Content SEO_ configuration designates useful defaults.
These SEO settings layer on top of each other, so the most specific value provided is always what is used for a given page. Content SEO settings override Global SEO settings, and SEO Settings fields override them both.
@@ -32,10 +29,37 @@ In this way, the SEO data that SEOmatic provides _cascades_ together to form the
## Twig Overrides
-SEOmatic also has a very robust Twig API for all of the SEO settings. For a given page, all of the SEO information provided by content authors cascades together as described above, and then is available in your Twig templates (or in PHP) for you to manipulate further as you see fit.
+You can work with and further manipulate the SEO information from that cascade using robust Twig and PHP APIs, for complete control over the SEO meta data that is rendered for your website.
+
+See [Using SEOmatic](./using/) for an in-depth look at how SEOmatic works under the hood, and for reference on the Twig APIs.
+
+## Plugin Support
+
+SEOmatic automatically works with the following plugins:
+
+* [Craft Commerce](https://plugins.craftcms.com/commerce) from Pixel & Tonic
+* [Digital Products](https://plugins.craftcms.com/digital-products) from Pixel & Tonic
+* [Calendar](https://plugins.craftcms.com/calendar) from Solspace
+* [Campaign](https://plugins.craftcms.com/campaign) from Put Your Lights On
+
+This means that SEOmatic will treat the Elements that these plugins provide as first class citizens, just like Craft Entries & Categories.
+
+SEOmatic will generate metadata, sitemaps, and have a Craft CP UI for them. If you have a custom Element provided by a plugin or module, you can integrate it using the [SeoElementInterface](https://github.com/nystudio107/craft-seomatic/blob/v4/src/base/SeoElementInterface.php).
+
+## Emoji Support
+
+SEOmatic supports using Emojis in any of the fields in SEOmatic, so you could use one in the SEO Description, for instance:
+
+![Screenshot of an SEO Settings field that includes emoji in a Custom Text description override](./resources/screenshots/seomatic-emoji-support.png)
+
+It’s up to Google whether or not to display the emojis that you add to your SEO meta, but used effectively, they can help make your entries in the SERP stand out from others. Learn more: [Why Use Emojis in Your SEO / PPC Strategy?](https://www.jellyfish.net/en-us/news-and-views/why-use-emojis-in-your-seo-ppc-strategy)
+
+![Screenshot of SEOmatic’s General settings in the Global SEO section, with the macOS emoji picker open and a boom emoji leading the global site title](./resources/screenshots/seomatic-mac-emoji-keyboard.png)
+
+On the Mac, you can invoke an Emoji keyboard inside of any text field by hitting Command Control Space. This works in any Mac application, not just web browsers or SEOmatic.
-In this way, you have complete control over the SEO meta data that is rendered for your website.
+## Single Page App (SPA) Support
-See the **Using SEOmatic** section for an in-depth look at how SEOmatic works under the hood, and for reference on the Twig APIs.
+SEOmatic fully supports working with SPAs, allowing you to receive the metadata needed for a given route either as an array, or as DOM elements ready to be inserted.
-Brought to you by [nystudio107](https://nystudio107.com/)
+See the [Headless SPA API](advanced.md#headless-spa-api) section for details.
diff --git a/docs/docs/resources.md b/docs/docs/resources.md
index b9c2829c2..1e9a7c34b 100644
--- a/docs/docs/resources.md
+++ b/docs/docs/resources.md
@@ -2,8 +2,11 @@
title: SEO Resources
description: SEO Resources documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
---
+
# SEO Resources
+Learn more about SEO goals, strategy, and tips.
+
## Crafting Modern SEO Presentation:
[![Crafting Modern SEO video](https://i.vimeocdn.com/video/671925645-ac6a1d9ae202eede970bc17a8438f8efe076e0a4be34eac8bfff83bad4885ac3-d?mw=1920&mh=1080&q=70)](http://dotall.com/sessions/seo-best-practices-from-a-developers-point-of-view)
@@ -21,5 +24,3 @@ description: SEO Resources documentation for the SEOmatic plugin. The SEOmatic p
* [Modern SEO: Snake Oil vs. Substance](https://nystudio107.com/blog/modern-seo-snake-oil-vs-substance)
* [JSON-LD, Structured Data and Erotica](https://nystudio107.com/blog/json-ld-structured-data-and-erotica)
-
-Brought to you by [nystudio107](https://nystudio107.com/)
diff --git a/docs/docs/resources/img/craft-cms-logo.png b/docs/docs/resources/img/craft-cms-logo.png
deleted file mode 100644
index bf334f2d8..000000000
Binary files a/docs/docs/resources/img/craft-cms-logo.png and /dev/null differ
diff --git a/docs/docs/resources/img/moz-logo-blue.png b/docs/docs/resources/img/moz-logo-blue.png
deleted file mode 100644
index f29b5f3fe..000000000
Binary files a/docs/docs/resources/img/moz-logo-blue.png and /dev/null differ
diff --git a/docs/docs/resources/screenshots/seomatic-global-security.png b/docs/docs/resources/screenshots/seomatic-global-security.png
deleted file mode 100644
index cbaba1a9e..000000000
Binary files a/docs/docs/resources/screenshots/seomatic-global-security.png and /dev/null differ
diff --git a/docs/docs/technologies.md b/docs/docs/technologies.md
deleted file mode 100644
index a15c0f6a7..000000000
--- a/docs/docs/technologies.md
+++ /dev/null
@@ -1,157 +0,0 @@
----
-title: SEO Technologies
-description: SEO Technologies documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
----
-# SEO Technologies
-
-## Pagination and SEO
-
-If you are using paginated entries, you’ll want to add some additional markup to your templates to make Google et al aware of this. Fortunately, SEOmatic makes that easy, you simply do:
-
-```twig
-{% do seomatic.helper.paginate(PAGEINFO) %}
-```
-
- The `PAGEINFO` here is the variable from the `{% paginate %}` tag as [described here](https://docs.craftcms.com/v3/templating/tags/paginate.html#the-pageInfo-variable), this will properly set the `canonicalUrl`, as well as adding the `` and `` tags for you.
-
-A complete example (just a modified version of the [Craft 3 Documentation on {% Paginate %}](https://docs.craftcms.com/v3/templating/tags/paginate.html#the-pageInfo-variable)) might look like this:
-
-```twig
-{% paginate craft.entries.section('blog').limit(10) as pageInfo, pageEntries %}
-{% do seomatic.helper.paginate(pageInfo) %}
-
-{% for entry in pageEntries %}
-
-
{{ entry.title }}
- {{ entry.body }}
-
-{% endfor %}
-
-{% if pageInfo.prevUrl %}Previous Page{% endif %}
-{% if pageInfo.nextUrl %}Next Page{% endif %}
-```
-More info: [SEO Guide to Google Webmaster Recommendations for Pagination](https://moz.com/blog/seo-guide-to-google-webmaster-recommendations-for-pagination)
-
-## Multi-Site Language/Locale Support
-
-SEOmatic comes with multi-site support baked in. Each site has its own localized settings that can be different on a per-site basis.
-
-Craft CMS [defines Sites](https://docs.craftcms.com/v3/sites.html) as any combination of site settings and locale (language). But there needs to be some way to organize these sites to define a relationship between them. That’s what [Site Groups](https://github.com/craftcms/cms/issues/1668) are for.
-
-SEOmatic treats each Site Group as a separate entity, and any sites contained in that site group are treated as localizations of the same site.
-
-This is necessary because there needs to be some way to let SEOmatic know what the relationship is between the various sites.
-
-So for example, you might have:
-
-```
-├── Primary Site Group
-│ ├── English Site
-│ ├── Chinese Site
-| └── German Site
-├── Sister Site Group
-│ ├── English Site
-| └── German Site
-```
-
-While you technically don’t have to organize your Site Groups in this manner, SEOmatic currently requires it so that it can understand the relationship between your sites.
-
-This is necessary because for a variety of SEO-related things, we need to tell search engines what is really just another localization/translation of the same thing.
-
-If you _don’t_ want to organize your sites in this manner, you’ll need to turn off the **Site Groups define logically separate sites** setting on the Plugin Settings page.
-
-Sites that are grouped together under the same Site Group will have `` & `` URLs added automatically in the HTML.
-
-To disable SEOmatic’s automatic rendering of these tags, you can do:
-```twig
-{% do seomatic.link.get('alternate').include(false) %}
-{% do seomatic.tag.get('og:locale:alternate').include(false) %}
-```
-
-Sites that are grouped together under the same Site Group will also be included in the appropriate sitemap indexes, and have `` tags added to the respective sitemaps.
-
-To disable the generation of the `` on a per-Entry basis, you can do this by adding an SEO Settings to the Section/Category Group/Product in question, and turn off **Sitemap Enabled** on a per-entry basis.
-
-## Plugin Support
-
-SEOmatic automatically works with the following plugins:
-
-* [Craft Commerce](https://plugins.craftcms.com/commerce) from Pixel & Tonic
-* [Digital Products](https://plugins.craftcms.com/digital-products) from Pixel & Tonic
-* [Calendar](https://plugins.craftcms.com/calendar) from Solspace
-
-This means that SEOmatic will treat the Elements that these plugins provide as first class citizens, just like Craft Entries & Categories.
-
-SEOmatic will generate metadata, sitemaps, and have a Craft CP UI for them. If you have a custom Element provided by a plugin or module, you can integrate it using the [SeoElementInterface](https://github.com/nystudio107/craft-seomatic/blob/v3/src/base/SeoElementInterface.php).
-
-## Emoji Support
-
-SEOmatic supports using Emojis in any of the fields in SEOmatic, so you could use one in the SEO Description, for instance:
-
-![Screenshot](./resources/screenshots/seomatic-emoji-support.png)
-
-It’s up to Google whether or not to display the emojis that you add to your SEO meta, but used effectively, they can help make your entries in the SERP stand out from others. Learn more: [Why Use Emojis in Your SEO / PPC Strategy?](https://www.jellyfish.net/en-us/news-and-views/why-use-emojis-in-your-seo-ppc-strategy)
-
-![Screenshot](./resources/screenshots/seomatic-mac-emoji-keyboard.png)
-
-On the Mac, you can invoke an Emoji keyboard inside of any text field by hitting Command Control Space. This works in any Mac application, not just web browsers or SEOmatic.
-
-## Google AMP Support
-
-SEOmatic works great with [Google AMP](https://www.ampproject.org/)! In fact, it will provide the [JSON-LD structured data](https://www.ampproject.org/docs/fundamentals/spec) that is _required_ by the AMP spec.
-
-You do however need to [Make your page discoverable](https://www.ampproject.org/docs/fundamentals/discovery):
-
-Add the following to the non-AMP template to tell Google where the AMP version of the page is; `yourAmpPageLink` the URL to your AMP page:
-
-```twig
-{% set linkTag = seomatic.link.create({
- "rel": "amphtml",
- "href": yourAmpPageLink
- })
-%}
-```
-
-And this to the AMP template to tell Google where the canonical HTML page is:
-
-```twig
-{% do seomatic.meta.canonicalUrl(entry.url) %}
-```
-
-Since AMP [doesn’t allow for third-party JavaScript](https://medium.com/google-developers/how-to-avoid-common-mistakes-when-publishing-accelerated-mobile-pages-9ea61abf530f), you might want to add this to your AMP templates:
-```twig
-{% do seomatic.script.container().include(false) %}
-```
-
-This will cause SEOmatic to not render _any_ custom scripts you might have enabled (such as Google Analytics, gtag, etc.)
-
-Then you can include Google AMP Analytics as per [Adding Analytics to your AMP pages](https://developers.google.com/analytics/devguides/collection/amp-analytics/) (this assumes you’re using `gtag`):
-```
-{% set script = seomatic.script.get('gtag') %}
-{% set analyticsId = script.vars.googleAnalyticsId.value ??? '' %}
-
-
-
-```
-
-The above uses the `???` empty coalesce operator that comes with SEOmatic; check out [SEOmatic’s ??? Empty Coalesce operator](#seomatics--empty-coalesce-operator) for details.
-
-## Single Page App (SPA) Support
-
-SEOmatic fully supports working with SPAs, allowing you to receive the metadata needed for a given route either as an array, or as DOM elements ready to be inserted.
-
-See the **Headless SPA API** section for details.
-
-Brought to you by [nystudio107](https://nystudio107.com/)
diff --git a/docs/docs/using.md b/docs/docs/using.md
deleted file mode 100644
index d068797b5..000000000
--- a/docs/docs/using.md
+++ /dev/null
@@ -1,841 +0,0 @@
----
-title: Using SEOmatic
-description: Using SEOmatic documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
----
-# Using SEOmatic
-
-## SEOmatic’s ??? Empty Coalesce operator
-
-SEOmatic adds the `???` operator to Twig that will return the first thing that is defined, not null, and not empty. This allows you to safely "cascade" empty text/image values.
-
-This can be used both in Twig templates, and in any of SEOmatic’s fields, which are parsed as Twig templates as well.
-
-This is particularly useful for SEO fields (both text & images), where you’re dealing with a number of fallback/default values that may or may not exist, and may or may not be empty.
-
-The `???` Empty Coalescing operator is similar to the `??` [null coalescing operator](https://nystudio107.com/blog/handling-errors-gracefully-in-craft-cms#coalescing-the-night-away), but also ignores empty strings (`""`) and empty arrays (`[]`) as well.
-
-The problem is that to [code defensively](https://nystudio107.com/blog/handling-errors-gracefully-in-craft-cms#defensive-coding-in-twig), you want to make sure that all of these things are defined, not null, and also have a value. So you end up with something like:
-
-```twig
-{% if entry is defined and entry.description is defined and entry.description | length %}
- {% set description = entry.description %}
-{% elseif category is defined and category.description is defined and category.description | length %}
- {% set description = category.description %}
-{% else %}
- {% set description = global.description %}
-{% endif %}
-```
-
-This gets quite verbose and quite tiresome quickly. There are other ways you can do something similar, such as using using the `?:` [ternary operator](https://twig.symfony.com/doc/2.x/templates.html#other-operators) and the [default filter](https://twig.symfony.com/doc/2.x/filters/default.html), but this too gets a bit unwieldy.
-
-You can use the [null coalescing operator](https://nystudio107.com/blog/handling-errors-gracefully-in-craft-cms#coalescing-the-night-away), which picks the first thing that is defined and not null:
-
-```twig
-{% set description = entry.description ?? category.description ?? global.description %}
-```
-
-But the problem here is it’ll _just_ pick the first thing that is defined and not `null`. So if `entry.description` is an empty string, it’ll use that, which is rarely what you want.
-
-Enter the Empty Coalescing operator, and it becomes:
-
-```twig
-{% set description = entry.description ??? category.description ??? global.description %}
-```
-
-Now the first thing that is defined, not null, _and_ not empty will be what `description` is set to.
-
-Nice. Simple. Readable. And most importantly, likely the result you’re expecting.
-
-The examples presented here use the `???` operator for SEOmatic functions, but you can use them for anything you like.
-
-We’ve submitted a [pull request](https://github.com/twigphp/Twig/pull/2787) in the hopes of making this part of Twig core. This functionality is also available separately in the [Empty Coalesce](https://nystudio107.com/plugins/empty-coalesce) plugin.
-
-## Twig Templating
-
-SEOmatic can work fully without any Twig templating code at all. However, it provides a robust API that you can tap into from your Twig templates should you desire to do so.
-
-SEOmatic makes a global `seomatic` variable available in your Twig templates that allows you to work with the SEOmatic variables and functions.
-
-## A Word About `{% cache %}` Tags
-
-If you use Craft’s built-in `{% cache %}` tags, ensure that you don’t have any of SEOmatic’s tags (listed below) inside of them. The reason is that SEOmatic dynamically generates the tags on each request, using its own caching system for performance reasons.
-
-When you surround any Twig code in a `{% cache %}` tag, that code will only ever be executed once. On subsequent runs, the HTML result of what was inside of the `{% cache %}` tag is just returned, and the Twig code inside of it is never executed.
-
-For more information on how the `{% cache %}` tag works, see the [The Craft {% cache %} Tag In-Depth](https://nystudio107.com/blog/the-craft-cache-tag-in-depth) article.
-
-## SEOmatic Variables
-
-All of the SEOmatic variables can be accessed as you would any normal Twig variable:
-
-```twig
-{{ seomatic.meta.seoTitle }}
-```
-Or
-```twig
-{% set title = seomatic.meta.seoTitle %}
-```
-
-They can also be changed by passing in a value with the Twig `{% do %}` syntax:
-
-```twig
-{% do seomatic.meta.seoTitle("Some Title") %}
-```
-Or
-```twig
-{% do seomatic.meta.seoDescription("This is my description. There are many like it, but this one is mine.") %}
-```
-
-You can also set multiple variables at once using array syntax:
-
-```twig
-{% do seomatic.meta.setAttributes({
- "seoTitle": "Some Title",
- "seoDescription": "This is my description. There are many like it, but this one is mine."
- })
-%}
-```
-
-Or you can chain them together:
-
-```twig
-{% do seomatic.meta
- .seoTitle("Some Title")
- .seoDescription("This is my description. There are many like it, but this one is mine.")
-%}
-```
-
-These do the same thing, so use whichever you prefer.
-
-You can set SEOmatic variables anywhere in your templates, even in sub-templates you `include` from other templates. This works because SEOmatic dynamically injects the meta tags, scripts, links, and JSON-LD into your page after the template is done rendering.
-
-SEOmatic variables can also reference other SEOmatic variables using single-bracket syntax:
-
- ```twig
- {% do seomatic.meta.seoDescription("{seomatic.meta.seoTitle}") %}
- ```
-
-You can also reference `entry`, `category`, or `product` Craft variables, if they are present in your template:
-
- ```twig
- {% do seomatic.meta.seoTitle("{entry.title}") %}
- ```
-Or
-```twig
- {% do seomatic.meta.seoTitle("{category.title}") %}
-```
-
-But most of the time, you’ll want to just set them like you would regular variables:
-
- ```twig
- {% do seomatic.meta.seoTitle(entry.title) %}
- ```
-Or
-```twig
- {% do seomatic.meta.seoTitle(category.title) %}
-```
-...so that there is no additional Twig parsing that needs to be done.
-
-SEOmatic variables are also parsed for aliases, and in Craft 3.1, for [environment variables](https://docs.craftcms.com/v3/config/environments.html#control-panel-settings) as well.
-
-There may be occasions where you want to output the final parsed value of an SEOmatic variable on the frontend. You can do that via `seomatic.meta.parsedValue()`. For example:
-
-```twig
-{{ seomatic.meta.parsedValue('seoDescription') }}
-```
-
-This will output the final parsed value of the `seomatic.meta.seoDescription` variable.
-
-This parsing is done automatically by SEOmatic just before the meta information is added to your page.
-
-## Meta Variables: `seomatic.meta`
-
-The `seomatic.meta` variable contains all of the meta variables that control the SEO that will be rendered on the site. They are pre-populated from your settings and content in the Control Panel, but you can change them as you see fit.
-
-### General Variables:
-
-* **`seomatic.meta.mainEntityOfPage`** - the [schema.org](http://schema.org/docs/full.html) type that represents the main entity of the page
-* **`seomatic.meta.seoTitle`** - the title that is used for the `` tag
-* **`seomatic.meta.siteNamePosition`** - controls where the `seomatic.site.siteName` appears relative to the `seomatic.meta.seoTitle` in the `` tag. Valid values are `before`, `after`, or `none`.
-* **`seomatic.meta.seoDescription`** - the description that is used for the `` tag
-* **`seomatic.meta.seoKeywords`** - the keywords that are used for the `` tag. Note that this tag is _ignored_ by Google
-* **`seomatic.meta.seoImage`** - the image URL that is used for SEO image
-* **`seomatic.meta.seoImageWidth`** - the width of the SEO image
-* **`seomatic.meta.seoImageHeight`** - the height of the SEO image
-* **`seomatic.meta.seoImageDescription`** - a textual description of the SEO image
-* **`seomatic.meta.canonicalUrl`** - the URL used for the `` tag. By default, this is set to `{seomatic.helper.safeCanonicalUrl()}` or `{entry.url}`/`{category.url}`/`{product.url}`, but you can change it as you see fit. This variable is also used to set the `link rel="canonical"` HTTP header.
-* **`seomatic.meta.robots`** - the setting used for the `` tag that controls how bots should index your site. This variable is also used to set the `X-Robots-Tag` HTTP header. [Learn More](https://developers.google.com/search/reference/robots_meta_tag)
-
-### Facebook OpenGraph Variables:
-
-* **`seomatic.meta.ogType`** - the value used for the `` tag, such as `website` or `article`
-* **`seomatic.meta.ogTitle`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoTitle}`
-* **`seomatic.meta.ogSiteNamePosition`** - controls where the `seomatic.site.siteName` appears relative to the `seomatic.meta.ogTitle` in the `` tag. Valid values are `before`, `after`, or `none`.
-* **`seomatic.meta.ogDescription`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoDescription}`
-* **`seomatic.meta.ogImage`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoImage}`
-* **`seomatic.meta.ogImageWidth`** - the width of the ogImage. This defaults to `{seomatic.meta.seoImageWidth}`
-* **`seomatic.meta.ogImageHeight`** - the height of the ogImage. This defaults to `{seomatic.meta.seoImageHeight}`
-* **`seomatic.meta.ogImageDescription`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoImageDescription}`
-
-### Twitter Variables:
-
-* **`seomatic.meta.twitterCard`** - the value used for the `` tag, such as `summary` or `summary_large_image`
-* **`seomatic.meta.twitterCreator`** - the value used for the `` tag. This defaults to `{seomatic.site.twitterHandle}`
-* **`seomatic.meta.twitterTitle`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoTitle}`
-* **`seomatic.meta.twitterSiteNamePosition`** - controls where the `seomatic.site.siteName` appears relative to the `seomatic.meta.twitterTitle` in the `` tag. Valid values are `before`, `after`, or `none`.
-* **`seomatic.meta.twitterDescription`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoDescription}`
-* **`seomatic.meta.twitterImage`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoImage}`
-* **`seomatic.meta.twitterImageWidth`** - the width of the Twitter image. This defaults to `{seomatic.meta.seoImageWidth}`
-* **`seomatic.meta.twitterImageHeight`** - the height of the Twitter image. This defaults to `{seomatic.meta.seoImageHeight}`
-* **`seomatic.meta.twitterImageDescription`** - the value used for the `` tag. This defaults to `{seomatic.meta.seoImageDescription}`
-
-## Site Variables `seomatic.site`
-
-The `seomatic.site` variable has site-wide settings that are available on a per-site basis for multi-site setups.
-
-* **`seomatic.site.siteName`** - The name of the site
-* **`seomatic.site.twitterHandle`** - The site Twitter handle
-* **`seomatic.site.facebookProfileId`** - The site Facebook profile ID
-* **`seomatic.site.facebookAppId`** - The site Facebook app ID
-* **`seomatic.site.googleSiteVerification`** - The Google Site Verification code
-* **`seomatic.site.bingSiteVerification`** - The Bing Site Verification code
-* **`seomatic.site.pinterestSiteVerification`** - The Pinterest Site Verification code
-* **`seomatic.site.sameAsLinks`** - Array of links for Same As... Sites, indexed by the handle. So for example you could access the site Facebook URL via `seomatic.site.sameAsLinks["facebook"]["url"]`. These links are used to generate the `` tags, and are also used in the `sameAs` property in the `mainEntityOfPage` JSON-LD.
-* **`seomatic.site.siteLinksSearchTarget`** - Google Site Links search target. [Learn More](https://developers.google.com/search/docs/data-types/sitelinks-searchbox)
-* **`seomatic.site.siteLinksQueryInput`** - Google Site Links query input. [Learn More](https://developers.google.com/search/docs/data-types/sitelinks-searchbox)
-
-### Site Identity Variables `seomatic.site.identity`
-
-The `seomatic.site.identity` variable is used to create [JSON-LD Structured Data](https://developers.google.com/search/docs/guides/intro-structured-data) that _can_ appear as [Rich Snippets](https://developers.google.com/search/docs/guides/mark-up-content) on Google Search Engine Results Pages (SERP). JSON-LD Structured Data helps computers understand context and relationships, and is also read by other social media sites and apps.
-
-The `seomatic.site.identity` encapsulates all of the information associated with the owner of the site.
-
-* **`seomatic.site.identity.siteType`** - The schema.org general type
-* **`seomatic.site.identity.siteSubType`** - The schema.org sub-type
-* **`seomatic.site.identity.siteSpecificType`** - The schema.org specific type
-* **`seomatic.site.identity.computedType`** - The computed most specific schema.org type
-* **`seomatic.site.identity.genericName`** - The name of the entity that owns the site
-* **`seomatic.site.identity.genericAlternateName`** - An alternate or nickname for the entity that owns the site
-* **`seomatic.site.identity.genericDescription`** - A description of the entity that owns the site
-* **`seomatic.site.identity.genericUrl`** - A URL for the entity that owns the site
-* **`seomatic.site.identity.genericImage`** - A URL to an image or logo that represents the entity that owns the site. The image must be in JPG, PNG, or GIF format.
-* **`seomatic.site.identity.genericImageWidth`** - The width of the entity image
-* **`seomatic.site.identity.genericImageHeight`** - The height of the entity image
-* **`seomatic.site.identity.genericImageIds`** - Asset ID array for the entity image
-* **`seomatic.site.identity.genericTelephone`** - The primary contact telephone number for the entity that owns the site
-* **`seomatic.site.identity.genericEmail`** - The primary contact email address for the entity that owns the site
-* **`seomatic.site.identity.genericStreetAddress`** - The street address of the entity that owns the website, for example: 123 Main Street
-* **`seomatic.site.identity.genericAddressLocality`** - locality of the entity that owns the website, for example: Portchester
-* **`seomatic.site.identity.genericAddressRegion`** - The region of the entity that owns the website, for example: New York or NY
-* **`seomatic.site.identity.genericPostalCode`** - The postal code of the entity that owns the website, for example: 14580
-* **`seomatic.site.identity.genericAddressCountry`** - The country in which the entity that owns the site is located, for example: US
-* **`seomatic.site.identity.genericGeoLatitude`** - The latitude of the location of the entity that owns the website, for example: -120.5436367
-* **`seomatic.site.identity.genericGeoLongitude`** - The longitude of the location of the entity that owns the website, for example: 80.6033588
-* **`seomatic.site.identity.personGender`** - Only for entities of the type Person, the gender of the person
-* **`seomatic.site.identity.personBirthPlace`** - Only for entities of the type Person, the place where the person was born
-* **`seomatic.site.identity.organizationDuns`** - Only for entities of the type Organization, the DUNS (Dunn & Bradstreet) number of the organization that owns the site
-* **`seomatic.site.identity.organizationFounder`** - Only for entities of the type Organization, the name of the founder of the organization
-* **`seomatic.site.identity.organizationFoundingDate`** - Only for entities of the type Organization, the date the organization/company/restaurant was founded in [ISO 8601 date format](http://schema.org/Date), for example: `2018-03-26`
-* **`seomatic.site.identity.organizationFoundingLocation`** - Only for entities of the type Organization, the location where the organization was founded
-* **`seomatic.site.identity.organizationContactPoints`** - Only for entities of the type Organization, an array of contact points for the organization. [Learn More](https://developers.google.com/search/docs/guides/enhance-site#provide-business-contact-markup)
-* **`seomatic.site.identity.corporationTickerSymbol`** - Only for entities of the type Corporation, the exchange ticker symbol of the corporation
-* **`seomatic.site.identity.localBusinessPriceRange`** - Only for entities of the type LocalBusiness, the approximate price range of the goods or services offered by this local business
-* **`seomatic.site.identity.localBusinessOpeningHours`** - Only for entities of the type LocalBusiness, an array of the opening hours for this local business. [Learn More][https://developers.google.com/search/docs/data-types/local-business]
-* **`seomatic.site.identity.restaurantServesCuisine`** - Only for entities of the type Food Establishment, the primary type of cuisine that the food establishment serves
-* **`seomatic.site.identity.restaurantMenuUrl`** - Only for entities of the type Food Establishment, a URL to the food establishment’s menu
-* **`seomatic.site.identity.restaurantReservationsUrl`** - Only for entities of the type Food Establishment, a URL to the food establishment’s reservations page
-
-### Site Creator Variables `seomatic.site.creator`
-
-The `seomatic.site.creator` variable is used to create [JSON-LD Structured Data](https://developers.google.com/search/docs/guides/intro-structured-data) that _can_ appear as [Rich Snippets](https://developers.google.com/search/docs/guides/mark-up-content) on Google Search Engine Results Pages (SERP). JSON-LD Structured Data helps computers understand context and relationships, and is also read by other social media sites and apps.
-
-The `seomatic.site.creator` encapsulates all of the information associated with the creator of the site. This information is also used in the `humans.txt` page
-
-* **`seomatic.site.creator.siteType`** - The schema.org general type
-* **`seomatic.site.creator.siteSubType`** - The schema.org sub-type
-* **`seomatic.site.creator.siteSpecificType`** - The schema.org specific type
-* **`seomatic.site.creator.computedType`** - The computed most specific schema.org type
-* **`seomatic.site.creator.genericName`** - The name of the entity that created the site
-* **`seomatic.site.creator.genericAlternateName`** - An alternate or nickname for the entity that created the site
-* **`seomatic.site.creator.genericDescription`** - A description of the entity that created the site
-* **`seomatic.site.creator.genericUrl`** - A URL for the entity that created the site
-* **`seomatic.site.creator.genericImage`** - A URL to an image or logo that represents the entity that created the site. The image must be in JPG, PNG, or GIF format.
-* **`seomatic.site.creator.genericImageWidth`** - The width of the entity image
-* **`seomatic.site.creator.genericImageHeight`** - The height of the entity image
-* **`seomatic.site.creator.genericImageIds`** - Asset ID array for the entity image
-* **`seomatic.site.creator.genericTelephone`** - The primary contact telephone number for the entity that created the site
-* **`seomatic.site.creator.genericEmail`** - The primary contact email address for the entity that created the site
-* **`seomatic.site.creator.genericStreetAddress`** - The street address of the entity that created the website, for example: 123 Main Street
-* **`seomatic.site.creator.genericAddressLocality`** - locality of the entity that created the website, for example: Portchester
-* **`seomatic.site.creator.genericAddressRegion`** - The region of the entity that created the website, for example: New York or NY
-* **`seomatic.site.creator.genericPostalCode`** - The postal code of the entity that created the website, for example: 14580
-* **`seomatic.site.creator.genericAddressCountry`** - The country in which the entity that created the site is located, for example: US
-* **`seomatic.site.creator.genericGeoLatitude`** - The latitude of the location of the entity that created the website, for example: -120.5436367
-* **`seomatic.site.creator.genericGeoLongitude`** - The longitude of the location of the entity that created the website, for example: 80.6033588
-* **`seomatic.site.creator.personGender`** - Only for entities of the type Person, the gender of the person
-* **`seomatic.site.creator.personBirthPlace`** - Only for entities of the type Person, the place where the person was born
-* **`seomatic.site.creator.organizationDuns`** - Only for entities of the type Organization, the DUNS (Dunn & Bradstreet) number of the organization that created the site
-* **`seomatic.site.creator.organizationFounder`** - Only for entities of the type Organization, the name of the founder of the organization
-* **`seomatic.site.creator.organizationFoundingDate`** - Only for entities of the type Organization, the date the organization/company/restaurant was founded in [ISO 8601 date format](http://schema.org/Date), for example: `2018-03-26`
-* **`seomatic.site.creator.organizationFoundingLocation`** - Only for entities of the type Organization, the location where the organization was founded
-* **`seomatic.site.creator.organizationContactPoints`** - Only for entities of the type Organization, an array of contact points for the organization. [Learn More](https://developers.google.com/search/docs/guides/enhance-site#provide-business-contact-markup)
-* **`seomatic.site.creator.corporationTickerSymbol`** - Only for entities of the type Corporation, the exchange ticker symbol of the corporation
-* **`seomatic.site.creator.localBusinessPriceRange`** - Only for entities of the type LocalBusiness, the approximate price range of the goods or services offered by this local business
-* **`seomatic.site.creator.localBusinessOpeningHours`** - Only for entities of the type LocalBusiness, an array of the opening hours for this local business. [Learn More][https://developers.google.com/search/docs/data-types/local-business]
-* **`seomatic.site.creator.restaurantServesCuisine`** - Only for entities of the type Food Establishment, the primary type of cuisine that the food establishment serves
-* **`seomatic.site.creator.restaurantMenuUrl`** - Only for entities of the type Food Establishment, a URL to the food establishment’s menu
-* **`seomatic.site.creator.restaurantReservationsUrl`** - Only for entities of the type Food Establishment, a URL to the food establishment’s reservations page
-
-## Config Variables `seomatic.config`
-
-The `seomatic.config` variables are the global plugin configuration variables set in the `config.php` file. You can copy the `config.php` file to the Craft `config/` directory as `seomatic.php` to change them in a multi-environment friendly way.
-
-* **`seomatic.config.pluginName`** - The public-facing name of the plugin
-* **`seomatic.config.renderEnabled`** - Should SEOmatic render metadata?
-* **`seomatic.config.environment`** - The server environment, either `live`, `staging`, or `local`
-* **`seomatic.config.displayPreviewSidebar`** - Should SEOmatic display the SEO Preview sidebar?
-* **`seomatic.config.displayAnalysisSidebar`** - Should SEOmatic display the SEO Analysis sidebar?
-* **`seomatic.config.devModeTitlePrefix`** - If `devMode` is on, prefix the `` with this string
-* **`seomatic.config.separatorChar`** - The separator character to use for the `` tag
-* **`seomatic.config.maxTitleLength`** - The max number of characters in the `` tag
-* **`seomatic.config.maxDescriptionLength`** - The max number of characters in the `` tag
-
-## Helper Functions `seomatic.helper`
-
-* **`seomatic.helper.paginate(PAGEINFO)`** - Given the `PAGEINFO` variable from the `{% paginate %}` tag as [described here](https://docs.craftcms.com/v3/templating/tags/paginate.html#the-pageInfo-variable), this will properly set the `canonicalUrl`, as well as adding the `` and `` tags for you.
-* **`seomatic.helper.isPreview()`** - returns `true` if the current request is a preview, `false` if it is not
-* **`seomatic.helper.sameAsByHandle(HANDLE)`** - returns an array of information about the **Same As URLs** site specified in `HANDLE`. Here’s an example of the information in the returned array:
-```
-array (size=4)
- 'siteName' => string 'Twitter'
- 'handle' => string 'twitter'
- 'url' => string 'https://twitter.com/nystudio107'
- 'account' => string 'nystudio107'
-```
-* **`seomatic.helper.truncate(TEXT, LENGTH, SUBSTR)`** - Truncates the `TEXT` to a given `LENGTH`. If `SUBSTR` is provided, and truncating occurs, the string is further truncated so that the substring may be appended without exceeding the desired length.
-* **`seomatic.helper.truncateOnWord(TEXT, LENGTH, SUBSTR)`** - Truncates the `TEXT` to a given `LENGTH`, while ensuring that it does not split words. If `SUBSTR` is provided, and truncating occurs, the string is further truncated so that the substring may be appended without exceeding the desired length.
-* **`seomatic.helper.getLocalizedUrls(URI, SITE_ID)`** - Return a list of localized URLs for a given `URI` that are in the `SITE_ID` site’s group. Both `URI` and `SITE_ID` are optional, and will use the current request’s `URI` and the current site’s `SITE_ID` if omitted.
-* **`seomatic.helper.loadMetadataForUri(URI, SITE_ID)`** - Load the appropriate meta containers for the given `URI` and optional `SITE_ID`
-* **`seomatic.helper.sitemapIndexForSiteId(SITE_ID)`** - Get the URL to the `SITE_ID`s sitemap index
-* **`seomatic.helper.extractTextFromField(FIELD)`** - Extract plain text from a PlainText, Redactor, CKEdtior, Tags, Matrix, or Neo field
-* **`seomatic.helper.extractKeywords(TEXT, LIMIT)`** - Extract up to `LIMIT` most important keywords from `TEXT`
-* **`seomatic.helper.extractSummary(TEXT)`** - Extract the most important 3 sentences from `TEXT`
-* **`seomatic.helper.socialTransform(ASSET, TRANSFORMNAME)`** - Transform the `ASSET` (either an Asset or an Asset ID) for social media sites in `TRANSFORMNAME`; valid values are `base`, `facebook`, `twitter-summary`, and `twitter-large`
-* **`seomatic.helper.seoFileLink(FILE_URL, ROBOTS, CANONICAL, INLINE)`** - Generates a link to a local or remote file that allows you to set the `X-Robots-Tag` header via `ROBOTS` (defaults to `all`) and `Link` canonical header via `CANONICAL` (defaults to `''`) as per [Advanced rel="canonical" HTTP Headers](https://moz.com/blog/how-to-advanced-relcanonical-http-headers). `INLINE` controls whether the file will be displayed inline or downloaded. If any values are empty `''`, the headers will not be included.
-* **`seomatic.helper.sanitizeUserInput(TEXT)`** - Sanitize the `TEXT` by decoding any HTML Entities, URL decoding the text, then removing any newlines, stripping HTML tags, stripping Twig tags, and changing single {}'s into ()'s
-
-## SEOmatic Tags & Containers
-
-All of the SEOmatic tags, links, scripts, title, and JSON-LD are meta objects that have their values set from the `seomatic.meta` variables.
-
-These meta objects know what properties they should have, and can self-validate. If `devMode` is on, you can check the Yii2 Debug Toolbar’s Log to see any validation warnings or errors with your tags.
-
-All of SEOmatic’s meta objects are stored in containers, and they can be accessed and manipulated directly. You can even dynamically create new tags via Twig at template render time.
-
-All of the meta object (tags, scripts, links, title, and JSON-LD) have the same API to make it easy to use.
-
-### Meta Object `.get()`
-```twig
-{% set descriptionTag = seomatic.tag.get("description") %}
-```
-...will return the `` meta object to you in `descriptionTag`.
-
-### Meta Object Properties
-
-You can access meta object properties just like you can any Twig variable:
-
-```twig
-{{ descriptionTag.content }}
-```
-Or
-```twig
-{% set myContent = seomatic.meta.seoTitle %}
-```
-
-They can also be changed by passing in a value with the Twig `{% do %}` syntax:
-
-
-```twig
-{% do descriptionTag.content("Some description") %}
-```
-
-All meta objects also have an `include` property that determines whether or not they should be included on your web page:
-
-```twig
-{% do descriptionTag.include(false) %}
-```
-
-You could also chain this together in a single line:
-```twig
-{% do seomatic.tag.get("description").include(false) %}
-```
-
-And you can set multiple attributes at once using an array syntax:
-
-```twig
-{% do seomatic.tag.get("description").setAttributes({
- "content": "Some Description",
- "include": false
- })
-%}
-```
-
-Which is the same as doing:
-
-
-```twig
-{% do seomatic.tag.get("description")
- .content("Some Description")
- .include(false)
-%}
-```
-
-So use whatever you like better.
-
-### Extra Tag Attributes
-
-Should you need to add extra tag attributes to a Meta Item, such as the various `data-` tags, you can do that with the `.tagAttrs` property:
-
-```twig
-{% set tag = seomatic.tag.get('description') %}
-{% if tag | length %}
- {% do tag.tagAttrs({
- "data-type": "lazy-description",
- }) %}
-{% endif %}
-```
-
-This will generate a tag that looks like this:
-```html
-
-```
-
-A more practical example would be using [Klaro](https://heyklaro.com/) to manage Cookie consent, etc. to not activate Google Analytics until consent is given:
-
-```twig
-{% set tag = seomatic.script.get('googleAnalytics') %}
-{% if tag | length %}
- {% do tag.tagAttrs({
- "type": "text/plain",
- "data-type": "application/javascript",
- "data-name": "google-analytics",
- }) %}
-{% endif %}
-```
-
-Then when the page renders in production, it’ll look like this:
-```html
-
-
-```
-
-For a complete list of the Script handles SEOmatic uses can be found in [ScriptContainer.php](https://github.com/nystudio107/craft-seomatic/blob/v3/src/seomatic-config/globalmeta/ScriptContainer.php)
-
-### Meta Object `.create()`
-
-To create a new meta object, you pass in a key:value array of the attributes to use when creating it:
-
-```twig
-{% set linkTag = seomatic.link.create({
- "rel": "canonical",
- "href": "https://nystudio107.com"
- })
-%}
-```
-
-By default, newly created meta objects are added to the appropriate meta container, so they will be rendered on the page. Should you wish to create a meta object but _not_ have it added to a container, you can pass in an optional `false` parameter:
-
-```twig
-{% set linkTag = seomatic.link.create({
- "rel": "canonical",
- "href": "https://nystudio107.com"
- }, false)
-%}
-```
-
-### Meta Object Validation
-
-All meta objects can self-validate:
-```twig
-{% set myJsonLd = seomatic.jsonLd.create({
- 'type': 'Article',
- 'name': 'Some Blog',
- 'url': 'woopsie',
-}) %}
-
-{% if myJsonLd.validate() %}
-
Valid!
-{% else %}
-
- {% for param,errors in myJsonLd.errors %}
-
- {{ param ~ " " }}
-
- {% for error in errors %}
-
- {{ error ~ " " }}
-
- {% endfor %}
-
-
- {% endfor %}
-
-{% endif %}
-```
-
-This will output:
-
-* URL
- * Must be one of these types: URL
-
-Which tells you that the `url` parameter is invalid. The default validation just ensures that all of the properties are correct.
-
-You can also set the _scenario_ to display properties that Google requires/recommends:
-
-```twig
-{% set myJsonLd = seomatic.jsonLd.create({
- 'type': 'Article',
- 'name': 'Some Blog',
- 'url': 'woopsie',
-}) %}
-
-{% do myJsonLd.setScenario('google') %}
-
-{% if myJsonLd.validate() %}
-
Valid!
-{% else %}
-
- {% for param,errors in myJsonLd.errors %}
-
- {{ param ~ " " }}
-
- {% for error in errors %}
-
- {{ error ~ " " }}
-
- {% endfor %}
-
-
- {% endfor %}
-
-{% endif %}
-```
-
-This will output:
-
-* URL
- * Must be one of these types: URL
-* Image
- * This property is recommended by Google.
-* Author
- * This property is required by Google.
-* DatePublished
- * This property is required by Google.
-* Headline
- * This property is required by Google.
-* Publisher
- * This property is required by Google.
-* MainEntityOfPage
- * This property is recommended by Google.
-* DateModified
- * This property is recommended by Google.
-
-If the site has `devMode` on, all of the meta objects are automatically validated as they are rendered, with the results displayed in the Yii Debug Toolbar. The Yii Debug Toolbar can be enabled in your account settings page.
-
-## JSON-LD Meta Object Functions `seomatic.jsonLd`
-
-* **`seomatic.jsonLd.get(META_HANDLE)`** Returns the JSON-LD meta object of the handle `META_HANDLE` or `null` if it is not found
-* **`seomatic.jsonLd.create()`** Creates a JSON-LD meta object from an array of key-value properties. The `type` can be any of the [Schema.org](http://schema.org/docs/full.html) types.
-* **`seomatic.jsonLd.add(META_OBJECT)`** Adds the `META_OBJECT` to the JSON-LD container to be rendered
-* **`seomatic.jsonLd.render()`** Renders all of the JSON-LD meta objects to your template. This is only needed if you have turned off **Automatic Render** in Plugin Settings
-* **`seomatic.jsonLd.container()`** Returns the container that holds an array of all of the JSON-LD meta objects
-
-### JSON-LD Meta Object Examples:
-
-Create a new [Article](http://schema.org/Article) JSON-LD meta object:
-```twig
-{% set myJsonLd = seomatic.jsonLd.create({
- 'type': 'Article',
- 'name': 'Some Blog',
- 'url': 'https://nystudio107.com/blog',
-}) %}
-```
-
-Get the existing **MainEntityOfPage** as set in the Global SEO or Content SEO Control Panel section to modify it (schema.org: [mainEntityOfPage](http://schema.org/docs/datamodel.html#mainEntityBackground)):
-```twig
-{% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %}
-```
-
-To add something to the existing **MainEntityOfPage** (in this case an [Offer](https://schema.org/Offer)), you can do it like this:
-```twig
-{% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %}
-
-{% set offersJsonLd = seomatic.jsonLd.create({
- 'type': 'Offer',
- 'name': 'Some prop',
- 'url': 'Some url',
-}, false) %}
-
-{% do mainEntity.offers(offersJsonLd) %}
-```
-
-The `, false` parameter tells it to create the JSON-LD object, but to _not_ automatically add it to the JSON-LD container. We do this because we don’t want it rendered on its own, we want it as part of the existing `mainEntityOfPage` JSON-LD object.
-
-Get the existing **BreadcrumbList** as generated automatically by SEOmatic to modify them (schema.org: [BreadcrumbList](http://schema.org/BreadcrumbList)):
-```twig
-{% set crumbs = seomatic.jsonLd.get('breadcrumbList') %}
-```
-
-Display the breadcrumbs on the page:
-
-```twig
-{% set crumbList = seomatic.jsonLd.get('breadcrumbList').itemListElement %}
-{% for crumb in crumbList %}
- {{ crumb.name }}
- {% if not loop.last %}»{% endif %}
-{% endfor %}
-```
-
-To entirely replace the existing **BreadcrumbList** on a page:
-```twig
-{% set crumbList = seomatic.jsonLd.create({
- 'type': 'BreadcrumbList',
- 'name': 'Breadcrumbs',
- 'description': 'Breadcrumbs list',
- 'itemListElement': [
- {
- 'type': 'ListItem',
- 'position': 1,
- 'name': 'Homepage',
- 'item': 'http://example.com/'
- },
- {
- 'type': 'ListItem',
- 'position': 2,
- 'name': 'Our blog',
- 'item': 'http://example.com/blog/'
- },
- {
- 'type': 'ListItem',
- 'position': 3,
- 'name': 'Technology blogs',
- 'item': 'http://example.com/blog/tech'
- },
- ]
-}) %}
-```
-
-If you need to create a schema element and propagate it, then use "key".
-Propagate **SiteNavigationElement**:
-```twig
- {% for nav in navigationMenu %}
- {% do seomatic.jsonLd.create({
- 'key': 'navItem' ~ nav.title,
- 'type': 'SiteNavigationElement',
- 'name': nav.title,
- 'url': nav.url
- }) %}
- {% endfor %}
-```
-
-Get the existing **Identity** as set in the Site Settings Control Panel section to modify it:
-```twig
-{% set identity = seomatic.jsonLd.get('identity') %}
-```
-
-Let’s say you want to add a [Brand](https://schema.org/Brand) to the **Identity**, you’d do this:
-
-```twig
-{% set identity = seomatic.jsonLd.get('identity') %}
-
-{% set brand = seomatic.jsonLd.create({
- 'type': 'Brand',
- 'name': 'Some prop',
- 'url': 'Some url',
-}, false) %}
-
-{% do identity.brand(brand) %}
-```
-
-The `, false` parameter tells it to create the JSON-LD object, but to _not_ automatically add it to the JSON-LD container. We do this because we don’t want it rendered on its own, we want it as part of the existing `mainEntityOfPage` JSON-LD object.
-
-Get the existing **Creator** as set in the Site Settings Control Panel section to modify it:
-```twig
-{% set identity = seomatic.jsonLd.get('creator') %}
-```
-
-## Link Meta Object Functions `seomatic.link`
-
-* **`seomatic.link.get(META_HANDLE)`** Returns the Link meta object of the handle `META_HANDLE` or `null` if it is not found
-* **`seomatic.link.create(CONFIG_ARRAY)`** Creates a Link meta object from an array of key-value properties
-* **`seomatic.link.add(META_OBJECT)`** Adds the `META_OBJECT` to the Link container to be rendered
-* **`seomatic.link.render()`** Renders all of the Link meta objects to your template. This is only needed if you have turned off **Automatic Render** in Plugin Settings
-* **`seomatic.link.container()`** Returns the container that holds an array of all of the Link meta objects
-
-### Link Meta Object Examples:
-
-Change the ``:
-```twig
-{% do seomatic.link.get("canonical").href("https://nystudio107.com") %}
-```
-
-Note that you can achieve the same result with:
-```twig
-{% do seomatic.meta.canonicalUrl("https://nystudio107.com") %}
-```
-
-...since the `canonicalUrl` populates the `` Link meta object
-
-To check what `alternate` links are rendered:
-
-```twig
- {% set alt = seomatic.link.get('alternate') %}
- {% do alt.href([
- 'http://example.com',
- 'http://example.com/es'
- ]).hreflang([
- 'x-default',
- 'es',
- ])
- %}
-```
-
-## Script Meta Object Functions `seomatic.script`
-
-* **`seomatic.script.get(META_HANDLE)`** Returns the Script meta object of the handle `META_HANDLE` or `null` if it is not found
-* **`seomatic.script.create()`** Creates a Script meta object from an array of key-value properties
-* **`seomatic.script.add(META_OBJECT)`** Adds the `META_OBJECT` to the Script container to be rendered
-* **`seomatic.script.render()`** Renders all of the Script meta objects to your template. This is only needed if you have turned off **Automatic Render** in Plugin Settings
-* **`seomatic.script.container()`** Returns the container that holds an array of all of the Script meta objects
-
-### Script Meta Object Examples:
-
-Don’t include the Google Analytics script on the page:
-```twig
-{% do seomatic.script.get("googleAnalytics").include(false) %}
-```
-
-For a complete list of the Script handles SEOmatic uses can be found in [ScriptContainer.php](https://github.com/nystudio107/craft-seomatic/blob/v3/src/seomatic-config/globalmeta/ScriptContainer.php)
-
-## Tag Meta Object Functions `seomatic.tag`
-
-* **`seomatic.tag.get(META_HANDLE)`** Returns the Tag meta object of the handle `META_HANDLE` or `null` if it is not found
-* **`seomatic.tag.create()`** Creates a Tag meta object from an array of key-value properties
-* **`seomatic.tag.add(META_OBJECT)`** Adds the `META_OBJECT` to the Tag container to be rendered
-* **`seomatic.tag.render()`** Renders all of the Tag meta objects to your template. This is only needed if you have turned off **Automatic Render** in Plugin Settings
-* **`seomatic.tag.container()`** Returns the container that holds an array of all of the Tag meta objects
-
-### Tag Meta Object Examples:
-
-Change the ``:
-
-```twig
-{% do seomatic.tag.get("twitter:title").content("Hello, world") %}
-```
-
-Note that you can achieve the same result with:
-```twig
-{% do seomatic.meta.twitterTitle("Hello, world") %}
-```
-
-...since the `twitterTitle` populates the `` Tag meta object by default.
-
-Let’s say you didn’t want Google et al to index a particular page or under certain conditions. You could do this:
-
-```twig
-{% do seomatic.tag.get("robots").content("none") %}
-```
-
-Note that you can achieve the same result with:
-```twig
-{% do seomatic.meta.robots("none") %}
-```
-
-...since the `robots` populates the `` Tag meta object by default.
-
-You can have multiple OpenGraph tags of the same time, for example `og:image`:
-
-```twig
-{% set ogImage = seomatic.tag.get('og:image') %}
-{% do ogImage.content([
- 'http://example.com/image1.jpg',
- 'http://example.com/image2.jpg',
-]) %}
-```
-
-...and it’ll generate a tag for each image:
-```html
-
-
-```
-
-## Title Meta Object Functions `seomatic.title`
-
-* **`seomatic.title.get(META_HANDLE)`** Returns the Title meta object of the handle `META_HANDLE` or `null` if it is not found
-* **`seomatic.title.create()`** Creates a Title meta object from an array of key/value properties
-* **`seomatic.title.add(META_OBJECT)`** Adds the `META_OBJECT` to the Title container to be rendered
-* **`seomatic.title.render()`** Renders Title meta object to your template. This is only needed if you have turned off **Automatic Render** in Plugin Settings
-* **`seomatic.title.container()`** Returns the container that holds an array with the Title meta object in it
-
-### Tag Meta Object Examples:
-
-Change the ``:
-
-```twig
-{% do seomatic.title.get("title").content("My page title") %}
-```
-
-Note that you can achieve the same result with:
-```twig
-{% do seomatic.meta.seoTitle("My page title") %}
-```
-
-...since the `seoTitle` populates the `` Title meta object
-
-## Meta Containers
-
-Normally you don’t need to work with meta containers directly, but SEOmatic gives you access to them to.
-
-You can get the meta container for each type of meta object by doing:
-
-```twig
-{% set jsonLdContainer = seomatic.jsonLd.container() %}
-{% set linkContainer = seomatic.link.container() %}
-{% set scriptContainer = seomatic.script.container() %}
-{% set tagContainer = seomatic.tag.container() %}
-{% set titleContainer = seomatic.title.container() %}
-```
-
-Then you can do things like tell an entire container to not render:
-
-```twig
-{% set scriptContainer = seomatic.script.container() %}
-{% do scriptContainer.include(false) %}
-```
-
-Or just:
-
-```twig
-{% do seomatic.script.container().include(false) %}
-```
-
-Containers are also cached. Typically SEOmatic manages this cache for you, but should you wish to invalidate the cache manually, you can do so via:
-
-```twig
-{% set scriptContainer = seomatic.script.container() %}
-{% do scriptContainer.clearCache(true) %}
-```
-
-Or just:
-
-```twig
-{% do seomatic.script.container().clearCache(true) %}
-```
-
-Brought to you by [nystudio107](https://nystudio107.com/)
diff --git a/docs/docs/using/config-variables.md b/docs/docs/using/config-variables.md
new file mode 100644
index 000000000..075c01de5
--- /dev/null
+++ b/docs/docs/using/config-variables.md
@@ -0,0 +1,13 @@
+# Config Variables
+
+The `seomatic.config` variables are the global plugin configuration variables set in the `config.php` file. You can copy the `config.php` file to the Craft `config/` directory as `seomatic.php` to change them in a multi-environment friendly way.
+
+* **`seomatic.config.pluginName`** – The public-facing name of the plugin.
+* **`seomatic.config.renderEnabled`** – Should SEOmatic render metadata?
+* **`seomatic.config.environment`** – The server environment, either `live`, `staging`, or `local`.
+* **`seomatic.config.displayPreviewSidebar`** – Should SEOmatic display the SEO Preview sidebar?
+* **`seomatic.config.displayAnalysisSidebar`** – Should SEOmatic display the SEO Analysis sidebar?
+* **`seomatic.config.devModeTitlePrefix`** – If `devMode` is on, prefix the `` with this string.
+* **`seomatic.config.separatorChar`** – The separator character to use for the `` tag.
+* **`seomatic.config.maxTitleLength`** – The max number of characters in the `` tag.
+* **`seomatic.config.maxDescriptionLength`** – The max number of characters in the `` tag.
diff --git a/docs/docs/using/empty-coalesce-operator.md b/docs/docs/using/empty-coalesce-operator.md
new file mode 100644
index 000000000..7872fca1d
--- /dev/null
+++ b/docs/docs/using/empty-coalesce-operator.md
@@ -0,0 +1,55 @@
+# Empty Coalesce Operator
+
+SEOmatic adds the `???` operator to Twig that will return the first thing that is defined, not null, and not empty. This allows you to safely "cascade" empty text/image values.
+
+This can be used both in Twig templates, and in any of SEOmatic’s fields, which are parsed as Twig templates as well.
+
+This is particularly useful for SEO fields (both text & images), where you’re dealing with a number of fallback/default values that may or may not exist, and may or may not be empty.
+
+The `???` Empty Coalescing operator is similar to the `??` [null coalescing operator](https://nystudio107.com/blog/handling-errors-gracefully-in-craft-cms#coalescing-the-night-away), but also ignores empty strings (`""`) and empty arrays (`[]`) as well.
+
+The problem is that to [code defensively](https://nystudio107.com/blog/handling-errors-gracefully-in-craft-cms#defensive-coding-in-twig), you want to make sure that all of these things are defined, not null, and also have a value. So you end up with something like:
+
+```twig
+{% if entry is defined and
+ entry.description is defined and
+ entry.description | length
+%}
+ {% set description = entry.description %}
+{% elseif category is defined and
+ category.description is defined and
+ category.description | length
+%}
+ {% set description = category.description %}
+{% else %}
+ {% set description = global.description %}
+{% endif %}
+```
+
+This gets quite verbose and quite tiresome quickly. There are other ways you can do something similar, such as using using the `?:` [ternary operator](https://twig.symfony.com/doc/2.x/templates.html#other-operators) and the [default filter](https://twig.symfony.com/doc/2.x/filters/default.html), but this too gets a bit unwieldy.
+
+You can use the [null coalescing operator](https://nystudio107.com/blog/handling-errors-gracefully-in-craft-cms#coalescing-the-night-away), which picks the first thing that is defined and not null:
+
+```twig
+{% set description = entry.description ??
+ category.description ??
+ global.description %}
+```
+
+But the problem here is it’ll _just_ pick the first thing that is defined and not `null`. So if `entry.description` is an empty string, it’ll use that, which is rarely what you want.
+
+Enter the Empty Coalescing operator, and it becomes:
+
+```twig
+{% set description = entry.description ???
+ category.description ???
+ global.description %}
+```
+
+Now `description` will be set to the first thing that is defined, not null, _and_ not empty.
+
+Nice. Simple. Readable. And most importantly, likely the result you’re expecting.
+
+The examples presented here use the `???` operator for SEOmatic functions, but you can use them for anything you like.
+
+We’ve submitted a [pull request](https://github.com/twigphp/Twig/pull/2787) in the hopes of making this part of Twig core. This functionality is also available separately in the [Empty Coalesce](https://nystudio107.com/plugins/empty-coalesce) plugin.
diff --git a/docs/docs/using/helper-functions.md b/docs/docs/using/helper-functions.md
new file mode 100644
index 000000000..d33992e8b
--- /dev/null
+++ b/docs/docs/using/helper-functions.md
@@ -0,0 +1,25 @@
+# Helper Functions
+
+The `seomatic.helper` functions are utilities that can help with pagination, previews, and preparing text and Assets.
+
+* **`seomatic.helper.paginate(PAGEINFO)`** – Given the `PAGEINFO` variable from the `{% paginate %}` tag as [described here](https://craftcms.com/docs/3.x/dev/tags.html#paginate), this will properly set the `canonicalUrl`, as well as adding the `` and `` tags for you.
+* **`seomatic.helper.isPreview()`** – Returns `true` if the current request is a preview, `false` if it is not.
+* **`seomatic.helper.sameAsByHandle(HANDLE)`** – Returns an array of information about the **Same As URLs** site specified in `HANDLE`. Here’s an example of the information in the returned array:
+ ```php
+ array (size=4)
+ 'siteName' => string 'Twitter'
+ 'handle' => string 'twitter'
+ 'url' => string 'https://twitter.com/nystudio107'
+ 'account' => string 'nystudio107'
+ ```
+* **`seomatic.helper.truncate(TEXT, LENGTH, SUBSTR)`** – Truncates the `TEXT` to a given `LENGTH`. If `SUBSTR` is provided, and truncating occurs, the string is further truncated so that the substring may be appended without exceeding the desired length.
+* **`seomatic.helper.truncateOnWord(TEXT, LENGTH, SUBSTR)`** – Truncates the `TEXT` to a given `LENGTH`, while ensuring that it does not split words. If `SUBSTR` is provided, and truncating occurs, the string is further truncated so that the substring may be appended without exceeding the desired length.
+* **`seomatic.helper.getLocalizedUrls(URI, SITE_ID)`** – Return a list of localized URLs for a given `URI` that are in the `SITE_ID` site’s group. Both `URI` and `SITE_ID` are optional, and will use the current request’s `URI` and the current site’s `SITE_ID` if omitted.
+* **`seomatic.helper.loadMetadataForUri(URI, SITE_ID)`** – Load the appropriate meta containers for the given `URI` and optional `SITE_ID`.
+* **`seomatic.helper.sitemapIndexForSiteId(SITE_ID)`** – Get the URL to the `SITE_ID`s sitemap index
+* **`seomatic.helper.extractTextFromField(FIELD)`** – Extract plain text from a PlainText, Redactor, CKEdtior, Tags, Matrix, or Neo field.
+* **`seomatic.helper.extractKeywords(TEXT, LIMIT)`** – Extract up to `LIMIT` most important keywords from `TEXT`.
+* **`seomatic.helper.extractSummary(TEXT)`** – Extract the most important 3 sentences from `TEXT`.
+* **`seomatic.helper.socialTransform(ASSET, TRANSFORMNAME)`** – Transform the `ASSET` (either an Asset or an Asset ID) for social media sites in `TRANSFORMNAME`; valid values are `base`, `facebook`, `twitter-summary`, and `twitter-large`.
+* **`seomatic.helper.seoFileLink(FILE_URL, ROBOTS, CANONICAL, INLINE)`** – Generates a link to a local or remote file that allows you to set the `X-Robots-Tag` header via `ROBOTS` (defaults to `all`) and `Link` canonical header via `CANONICAL` (defaults to `''`) as per [Advanced rel="canonical" HTTP Headers](https://moz.com/blog/how-to-advanced-relcanonical-http-headers). `INLINE` controls whether the file will be displayed inline or downloaded. If any values are empty `''`, the headers will not be included.
+* **`seomatic.helper.sanitizeUserInput(TEXT)`** – Sanitize the `TEXT` by decoding any HTML Entities, URL decoding the text, then removing any newlines, stripping HTML tags, stripping Twig tags, and changing single {}'s into ()'s.
diff --git a/docs/docs/using/index.md b/docs/docs/using/index.md
new file mode 100644
index 000000000..2d54df096
--- /dev/null
+++ b/docs/docs/using/index.md
@@ -0,0 +1,331 @@
+---
+title: Twig Templating
+description: Using SEOmatic documentation for the SEOmatic plugin. The SEOmatic plugin facilitates modern SEO best practices & implementation for Craft CMS 3.
+---
+
+# Twig Templating
+
+SEOmatic can work fully without any Twig templating code at all. However, it provides a robust API that you can tap into from your Twig templates should you desire to do so.
+
+SEOmatic makes a global `seomatic` variable available in your Twig templates that allows you to work with the SEOmatic variables and functions.
+
+## A Word About `{% cache %}` Tags
+
+If you use Craft’s built-in `{% cache %}` tags, ensure that you don’t have any of SEOmatic’s tags (listed below) inside of them. The reason is that SEOmatic dynamically generates the tags on each request, using its own caching system for performance reasons.
+
+When you surround any Twig code in a `{% cache %}` tag, that code will only ever be executed once. On subsequent runs, the HTML result of what was inside of the `{% cache %}` tag is just returned, and the Twig code inside of it is never executed.
+
+For more information on how the `{% cache %}` tag works, see the [The Craft {% cache %} Tag In-Depth](https://nystudio107.com/blog/the-craft-cache-tag-in-depth) article.
+
+## SEOmatic Variables
+
+All of the SEOmatic variables can be accessed as you would any normal Twig variable:
+
+```twig
+{{ seomatic.meta.seoTitle }}
+```
+Or
+```twig
+{% set title = seomatic.meta.seoTitle %}
+```
+
+They can also be changed by passing in a value with the Twig `{% do %}` syntax:
+
+```twig
+{% do seomatic.meta.seoTitle("Some Title") %}
+```
+Or
+```twig
+{% do seomatic.meta.seoDescription(
+ "This is my description. There are many like it, but this one is mine."
+) %}
+```
+
+You can also set multiple variables at once using array syntax:
+
+```twig
+{% do seomatic.meta.setAttributes({
+ "seoTitle": "Some Title",
+ "seoDescription": "This is my description. There are many like it..."
+}) %}
+```
+
+Or you can chain them together:
+
+```twig
+{% do seomatic.meta
+ .seoTitle("Some Title")
+ .seoDescription("This is my description. There are many like it...") %}
+```
+
+These do the same thing, so use whichever you prefer.
+
+You can set SEOmatic variables anywhere in your templates, even in sub-templates you `include` from other templates. This works because SEOmatic dynamically injects the meta tags, scripts, links, and JSON-LD into your page after the template is done rendering.
+
+SEOmatic variables can also reference other SEOmatic variables using single-bracket syntax:
+
+```twig
+{% do seomatic.meta.seoDescription("{seomatic.meta.seoTitle}") %}
+```
+
+You can also reference `entry`, `category`, or `product` Craft variables, if they are present in your template:
+
+```twig
+{% do seomatic.meta.seoTitle("{entry.title}") %}
+```
+
+Or
+
+```twig
+{% do seomatic.meta.seoTitle("{category.title}") %}
+```
+
+But most of the time, you’ll want to just set them like you would regular variables:
+
+```twig
+{% do seomatic.meta.seoTitle(entry.title) %}
+```
+
+Or
+
+```twig
+{% do seomatic.meta.seoTitle(category.title) %}
+```
+
+...so that there is no additional Twig parsing that needs to be done.
+
+SEOmatic variables are also parsed for aliases, and in Craft 3.1, for [environment variables](https://craftcms.com/docs/3.x/config/#control-panel-settings) as well.
+
+There may be occasions where you want to output the final parsed value of an SEOmatic variable on the front end. You can do that via `seomatic.meta.parsedValue()`. For example:
+
+```twig
+{{ seomatic.meta.parsedValue('seoDescription') }}
+```
+
+This will output the final parsed value of the `seomatic.meta.seoDescription` variable.
+
+This parsing is done automatically by SEOmatic just before the meta information is added to your page.
+
+## Tags & Containers
+
+All of the SEOmatic tags, links, scripts, title, and JSON-LD are meta objects that have their values set from the `seomatic.meta` variables.
+
+These meta objects know what properties they should have, and can self-validate. If `devMode` is on, you can check the Yii2 Debug Toolbar’s Log to see any validation warnings or errors with your tags.
+
+All of SEOmatic’s meta objects are stored in containers, and they can be accessed and manipulated directly. You can even dynamically create new tags via Twig at template render time.
+
+All of the meta object (tags, scripts, links, title, and JSON-LD) have the same API to make it easy to use.
+
+### Meta Object `.get()`
+
+```twig
+{% set descriptionTag = seomatic.tag.get("description") %}
+```
+
+...will return the `` meta object to you in `descriptionTag`.
+
+### Meta Object Properties
+
+You can access meta object properties just like you can any Twig variable:
+
+```twig
+{{ descriptionTag.content }}
+```
+
+Or
+
+```twig
+{% set myContent = seomatic.meta.seoTitle %}
+```
+
+They can also be changed by passing in a value with the Twig `{% do %}` syntax:
+
+```twig
+{% do descriptionTag.content("Some description") %}
+```
+
+All meta objects also have an `include` property that determines whether or not they should be included on your web page:
+
+```twig
+{% do descriptionTag.include(false) %}
+```
+
+You could also chain this together in a single line:
+
+```twig
+{% do seomatic.tag.get("description").include(false) %}
+```
+
+And you can set multiple attributes at once using an array syntax:
+
+```twig
+{% do seomatic.tag.get("description").setAttributes({
+ "content": "Some Description",
+ "include": false
+}) %}
+```
+
+Which is the same as doing:
+
+```twig
+{% do seomatic.tag.get("description")
+ .content("Some Description")
+ .include(false) %}
+```
+
+So use whatever you like better.
+
+### Extra Tag Attributes
+
+Should you need to add extra tag attributes to a Meta Item, such as the various `data-` tags, you can do that with the `.tagAttrs` property:
+
+```twig
+{% set tag = seomatic.tag.get('description') %}
+{% if tag | length %}
+ {% do tag.tagAttrs({
+ "data-type": "whatever",
+ }) %}
+{% endif %}
+```
+
+This will generate a tag like this:
+
+```html
+
+```
+
+A more practical example would be using [Klaro](https://heyklaro.com/) to manage Cookie consent, etc. to not activate Google Analytics until consent is given:
+
+```twig
+{% set tag = seomatic.script.get('googleAnalytics') %}
+{% if tag | length %}
+ {% do tag.tagAttrs({
+ "type": "text/plain",
+ "data-type": "application/javascript",
+ "data-name": "google-analytics",
+ }) %}
+{% endif %}
+```
+
+Then when the page renders in production, it’ll look like this:
+```html
+
+```
+
+See [ScriptContainer.php](https://github.com/nystudio107/craft-seomatic/blob/v4/src/seomatic-config/globalmeta/ScriptContainer.php) for a complete list of the script handles SEOmatic uses.
+
+### Meta Object `.create()`
+
+To create a new meta object, you pass in a key:value array of the attributes to use when creating it:
+
+```twig
+{% set linkTag = seomatic.link.create({
+ "rel": "canonical",
+ "href": "https://nystudio107.com"
+}) %}
+```
+
+By default, newly created meta objects are added to the appropriate meta container, so they will be rendered on the page. Should you wish to create a meta object but _not_ have it added to a container, you can pass in an optional `false` parameter:
+
+```twig
+{% set linkTag = seomatic.link.create({
+ "rel": "canonical",
+ "href": "https://nystudio107.com"
+}, false) %}
+```
+
+### Meta Object Validation
+
+All meta objects can self-validate:
+
+```twig
+{% set myJsonLd = seomatic.jsonLd.create({
+ 'type': 'Article',
+ 'name': 'Some Blog',
+ 'url': 'woopsie',
+}) %}
+
+{% if myJsonLd.validate() %}
+
Valid!
+{% else %}
+
+ {% for param,errors in myJsonLd.errors %}
+
+ {{ param ~ " " }}
+
+ {% for error in errors %}
+
+ {{ error ~ " " }}
+
+ {% endfor %}
+
+
+ {% endfor %}
+
+{% endif %}
+```
+
+This will output:
+
+* URL
+ * Must be one of these types: URL
+
+Which tells you that the `url` parameter is invalid. The default validation just ensures that all of the properties are correct.
+
+You can also set the _scenario_ to display properties that Google requires/recommends:
+
+```twig
+{% set myJsonLd = seomatic.jsonLd.create({
+ 'type': 'Article',
+ 'name': 'Some Blog',
+ 'url': 'woopsie',
+}) %}
+
+{% do myJsonLd.setScenario('google') %}
+
+{% if myJsonLd.validate() %}
+
Valid!
+{% else %}
+
+ {% for param,errors in myJsonLd.errors %}
+
+ {{ param ~ " " }}
+
+ {% for error in errors %}
+
+ {{ error ~ " " }}
+
+ {% endfor %}
+
+
+ {% endfor %}
+
+{% endif %}
+```
+
+This will output:
+
+* URL
+ * Must be one of these types: URL
+* Image
+ * This property is recommended by Google.
+* Author
+ * This property is required by Google.
+* DatePublished
+ * This property is required by Google.
+* Headline
+ * This property is required by Google.
+* Publisher
+ * This property is required by Google.
+* MainEntityOfPage
+ * This property is recommended by Google.
+* DateModified
+ * This property is recommended by Google.
+
+If the site has `devMode` on, all of the meta objects are automatically validated as they are rendered, with the results displayed in the Yii Debug Toolbar. The Yii Debug Toolbar can be enabled in your account settings page.
diff --git a/docs/docs/using/json-ld-meta.md b/docs/docs/using/json-ld-meta.md
new file mode 100644
index 000000000..9bd904608
--- /dev/null
+++ b/docs/docs/using/json-ld-meta.md
@@ -0,0 +1,126 @@
+# JSON-LD Meta Object Functions
+
+The `seomatic.jsonLd` functions make it easier to create, manipulate, and render valid JSON-LD microdata.
+
+* **`seomatic.jsonLd.get(META_HANDLE)`** – Returns the JSON-LD meta object of the handle `META_HANDLE` or `null` if it is not found.
+* **`seomatic.jsonLd.create()`** – Creates a JSON-LD meta object from an array of key-value properties. The `type` can be any of the [Schema.org](http://schema.org/docs/full.html) types.
+* **`seomatic.jsonLd.add(META_OBJECT)`** – Adds the `META_OBJECT` to the JSON-LD container to be rendered.
+* **`seomatic.jsonLd.render()`** – Renders all of the JSON-LD meta objects to your template. Only necessary if you’ve disabled **Automatic Render** in [Plugin Settings](../configuring/plugin-settings.md).
+* **`seomatic.jsonLd.container()`** – Returns the container that holds an array of all of the JSON-LD meta objects.
+
+## JSON-LD Meta Object Examples:
+
+Create a new [Article](http://schema.org/Article) JSON-LD meta object:
+
+```twig
+{% set myJsonLd = seomatic.jsonLd.create({
+ 'type': 'Article',
+ 'name': 'Some Blog',
+ 'url': 'https://nystudio107.com/blog',
+}) %}
+```
+
+Get the existing **MainEntityOfPage** as set in the Global SEO or Content SEO control panel section to modify it (schema.org: [mainEntityOfPage](http://schema.org/docs/datamodel.html#mainEntityBackground)):
+```twig
+{% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %}
+```
+
+To add something to the existing **MainEntityOfPage** (in this case an [Offer](https://schema.org/Offer)), you can do it like this:
+```twig
+{% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %}
+
+{% set offersJsonLd = seomatic.jsonLd.create({
+ 'type': 'Offer',
+ 'name': 'Some prop',
+ 'url': 'Some url',
+}, false) %}
+
+{% do mainEntity.offers(offersJsonLd) %}
+```
+
+The `, false` parameter tells it to create the JSON-LD object, but to _not_ automatically add it to the JSON-LD container. We do this because we don’t want it rendered on its own, we want it as part of the existing `mainEntityOfPage` JSON-LD object.
+
+Get the existing **BreadcrumbList** as generated automatically by SEOmatic to modify them (schema.org: [BreadcrumbList](http://schema.org/BreadcrumbList)):
+```twig
+{% set crumbs = seomatic.jsonLd.get('breadcrumbList') %}
+```
+
+Display the breadcrumbs on the page:
+
+```twig
+{% set crumbList = seomatic.jsonLd.get('breadcrumbList').itemListElement %}
+{% for crumb in crumbList %}
+ {{ crumb.name }}
+ {% if not loop.last %}»{% endif %}
+{% endfor %}
+```
+
+To replace the existing **BreadcrumbList** on a page:
+
+```twig
+{% set crumbList = seomatic.jsonLd.create({
+ 'type': 'BreadcrumbList',
+ 'name': 'Breadcrumbs',
+ 'description': 'Breadcrumbs list',
+ 'itemListElement': [
+ {
+ 'type': 'ListItem',
+ 'position': 1,
+ 'name': 'Homepage',
+ 'item': 'http://example.com/'
+ },
+ {
+ 'type': 'ListItem',
+ 'position': 2,
+ 'name': 'Our blog',
+ 'item': 'http://example.com/blog/'
+ },
+ {
+ 'type': 'ListItem',
+ 'position': 3,
+ 'name': 'Technology blogs',
+ 'item': 'http://example.com/blog/tech'
+ },
+ ]
+}) %}
+```
+
+Use `key` to create a schema element and propagate it. Propagate **SiteNavigationElement**:
+
+```twig
+{% for nav in navigationMenu %}
+ {% do seomatic.jsonLd.create({
+ 'key': 'navItem' ~ nav.title,
+ 'type': 'SiteNavigationElement',
+ 'name': nav.title,
+ 'url': nav.url
+ }) %}
+{% endfor %}
+```
+
+Get the existing **Identity** as set in the Site Settings control panel section to modify it:
+
+```twig
+{% set identity = seomatic.jsonLd.get('identity') %}
+```
+
+Let’s say you want to add a [Brand](https://schema.org/Brand) to the **Identity**, you’d do this:
+
+```twig
+{% set identity = seomatic.jsonLd.get('identity') %}
+
+{% set brand = seomatic.jsonLd.create({
+ 'type': 'Brand',
+ 'name': 'Some prop',
+ 'url': 'Some url',
+}, false) %}
+
+{% do identity.brand(brand) %}
+```
+
+The `, false` parameter tells it to create the JSON-LD object, but to _not_ automatically add it to the JSON-LD container. We do this because we don’t want it rendered on its own, we want it as part of the existing `mainEntityOfPage` JSON-LD object.
+
+Get the existing **Creator** as set in the Site Settings control panel section to modify it:
+```twig
+{% set identity = seomatic.jsonLd.get('creator') %}
+```
diff --git a/docs/docs/using/link-meta.md b/docs/docs/using/link-meta.md
new file mode 100644
index 000000000..7b9ca9958
--- /dev/null
+++ b/docs/docs/using/link-meta.md
@@ -0,0 +1,36 @@
+# Link Meta Object Functions
+
+The `seomatic.link` functions are for working with `` tags.
+
+* **`seomatic.link.get(META_HANDLE)`** – Returns the Link meta object of the handle `META_HANDLE` or `null` if it is not found.
+* **`seomatic.link.create(CONFIG_ARRAY)`** – Creates a Link meta object from an array of key-value properties.
+* **`seomatic.link.add(META_OBJECT)`** – Adds the `META_OBJECT` to the Link container to be rendered.
+* **`seomatic.link.render()`** – Renders all of the Link meta objects to your template. Only necessary if you’ve disabled **Automatic Render** in [Plugin Settings](../configuring/plugin-settings.md).
+* **`seomatic.link.container()`** – Returns the container that holds an array of all of the Link meta objects.
+
+## Link Meta Object Examples:
+
+Change the ``:
+```twig
+{% do seomatic.link.get("canonical").href("https://nystudio107.com") %}
+```
+
+Note that you can achieve the same result with:
+```twig
+{% do seomatic.meta.canonicalUrl("https://nystudio107.com") %}
+```
+
+...since the `canonicalUrl` populates the `` Link meta object
+
+To check what `alternate` links are rendered:
+
+```twig
+{% set alt = seomatic.link.get('alternate') %}
+{% do alt.href([
+ 'http://example.com',
+ 'http://example.com/es'
+]).hreflang([
+ 'x-default',
+ 'es',
+]) %}
+```
diff --git a/docs/docs/using/meta-containers.md b/docs/docs/using/meta-containers.md
new file mode 100644
index 000000000..3bc03a51e
--- /dev/null
+++ b/docs/docs/using/meta-containers.md
@@ -0,0 +1,39 @@
+# Meta Containers
+
+Normally you don’t need to work with meta containers directly, but SEOmatic gives you access to them too.
+
+You can get the meta container for each type of meta object by doing:
+
+```twig
+{% set jsonLdContainer = seomatic.jsonLd.container() %}
+{% set linkContainer = seomatic.link.container() %}
+{% set scriptContainer = seomatic.script.container() %}
+{% set tagContainer = seomatic.tag.container() %}
+{% set titleContainer = seomatic.title.container() %}
+```
+
+Then you can do things like tell an entire container to not render:
+
+```twig
+{% set scriptContainer = seomatic.script.container() %}
+{% do scriptContainer.include(false) %}
+```
+
+Or just:
+
+```twig
+{% do seomatic.script.container().include(false) %}
+```
+
+Containers are also cached. Typically SEOmatic manages this cache for you, but should you wish to invalidate the cache manually, you can do so via:
+
+```twig
+{% set scriptContainer = seomatic.script.container() %}
+{% do scriptContainer.clearCache(true) %}
+```
+
+Or just:
+
+```twig
+{% do seomatic.script.container().clearCache(true) %}
+```
diff --git a/docs/docs/using/meta-variables.md b/docs/docs/using/meta-variables.md
new file mode 100644
index 000000000..a276f7861
--- /dev/null
+++ b/docs/docs/using/meta-variables.md
@@ -0,0 +1,41 @@
+# Meta Variables
+
+The `seomatic.meta` variable contains all of the meta variables that control the SEO that will be rendered on the site. They are pre-populated from your settings and content in the control panel, but you can change them as you see fit.
+
+## General Variables
+
+* **`seomatic.meta.mainEntityOfPage`** – The [schema.org](http://schema.org/docs/full.html) type that represents the main entity of the page.
+* **`seomatic.meta.seoTitle`** – The title that is used for the `` tag.
+* **`seomatic.meta.siteNamePosition`** – controls where the `seomatic.site.siteName` appears relative to the `seomatic.meta.seoTitle` in the `` tag. Valid values are `before`, `after`, or `none`.
+* **`seomatic.meta.seoDescription`** – The description that is used for the `` tag.
+* **`seomatic.meta.seoKeywords`** – The keywords that are used for the `` tag. Note that this tag is _ignored_ by Google.
+* **`seomatic.meta.seoImage`** – The image URL that is used for SEO image.
+* **`seomatic.meta.seoImageWidth`** – The width of the SEO image.
+* **`seomatic.meta.seoImageHeight`** – The height of the SEO image.
+* **`seomatic.meta.seoImageDescription`** – A textual description of the SEO image.
+* **`seomatic.meta.canonicalUrl`** – The URL used for the `` tag. By default, this is set to `{seomatic.helper.safeCanonicalUrl()}` or `{entry.url}`/`{category.url}`/`{product.url}`, but you can change it as you see fit. This variable is also used to set the `link rel="canonical"` HTTP header.
+* **`seomatic.meta.robots`** – The setting used for the `` tag that controls how bots should index your site. This variable is also used to set the `X-Robots-Tag` HTTP header. [Learn More](https://developers.google.com/search/reference/robots_meta_tag)
+
+## Facebook Open Graph Variables
+
+* **`seomatic.meta.ogType`** – The value used for the `` tag, such as `website` or `article`.
+* **`seomatic.meta.ogTitle`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoTitle}`.
+* **`seomatic.meta.ogSiteNamePosition`** – controls where the `seomatic.site.siteName` appears relative to the `seomatic.meta.ogTitle` in the `` tag. Valid values are `before`, `after`, or `none`.
+* **`seomatic.meta.ogDescription`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoDescription}`.
+* **`seomatic.meta.ogImage`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoImage}`.
+* **`seomatic.meta.ogImageWidth`** – The width of the ogImage. This defaults to `{seomatic.meta.seoImageWidth}`.
+* **`seomatic.meta.ogImageHeight`** – The height of the ogImage. This defaults to `{seomatic.meta.seoImageHeight}`.
+* **`seomatic.meta.ogImageDescription`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoImageDescription}`.
+
+## Twitter Variables
+
+* **`seomatic.meta.twitterCard`** – The value used for the `` tag, such as `summary` or `summary_large_image`.
+* **`seomatic.meta.twitterCreator`** – The value used for the `` tag. This defaults to `{seomatic.site.twitterHandle}`.
+* **`seomatic.meta.twitterTitle`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoTitle}`.
+* **`seomatic.meta.twitterSiteNamePosition`** – controls where the `seomatic.site.siteName` appears relative to the `seomatic.meta.twitterTitle` in the `` tag. Valid values are `before`, `after`, or `none`.
+* **`seomatic.meta.twitterDescription`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoDescription}`.
+* **`seomatic.meta.twitterImage`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoImage}`.
+* **`seomatic.meta.twitterImageWidth`** – The width of the Twitter image. This defaults to `{seomatic.meta.seoImageWidth}`.
+* **`seomatic.meta.twitterImageHeight`** – The height of the Twitter image. This defaults to `{seomatic.meta.seoImageHeight}`.
+* **`seomatic.meta.twitterImageDescription`** – The value used for the `` tag. This defaults to `{seomatic.meta.seoImageDescription}`.
+
diff --git a/docs/docs/using/pagination.md b/docs/docs/using/pagination.md
new file mode 100644
index 000000000..28006a8af
--- /dev/null
+++ b/docs/docs/using/pagination.md
@@ -0,0 +1,35 @@
+# Pagination & SEO
+
+If you are using paginated entries, you’ll want to add some additional markup to your templates to make Google et al aware of this. Fortunately, SEOmatic makes that easy, you simply do:
+
+```twig
+{% do seomatic.helper.paginate(PAGEINFO) %}
+```
+
+The `PAGEINFO` here is the variable from the `{% paginate %}` tag as [described here](https://craftcms.com/docs/3.x/dev/tags.html#paginate), this will properly set the `canonicalUrl`, as well as adding the `` and `` tags for you.
+
+A complete example (following [Craft’s {% paginate %} documentation](https://craftcms.com/docs/3.x/dev/tags.html#paginate)) might look like this:
+
+```twig{4}
+{% paginate craft.entries()
+ .section('blog')
+ .limit(10) as pageInfo, pageEntries %}
+{% do seomatic.helper.paginate(pageInfo) %}
+
+{% for entry in pageEntries %}
+
+
{{ entry.title }}
+ {{ entry.body }}
+
+{% endfor %}
+
+{% if pageInfo.prevUrl %}
+ Previous Page
+{% endif %}
+
+{% if pageInfo.nextUrl %}
+ Next Page
+{% endif %}
+```
+
+More info: [SEO Guide to Google Webmaster Recommendations for Pagination](https://moz.com/blog/seo-guide-to-google-webmaster-recommendations-for-pagination)
diff --git a/docs/docs/using/script-meta.md b/docs/docs/using/script-meta.md
new file mode 100644
index 000000000..098efcc1f
--- /dev/null
+++ b/docs/docs/using/script-meta.md
@@ -0,0 +1,19 @@
+# Script Meta Object Functions
+
+The `seomatic.script` functions are for working with `