wanze / SeoMaestro

🧙‍♂️A ProcessWire module helping you to manage SEO related tasks like a boss.
MIT License
34 stars 9 forks source link
metatags processwire processwire-modules seo sitemap-xml

Seo Maestro

StyleCI License: MIT ProcessWire 3

A ProcessWire module helping you to manage SEO related tasks like a boss! 😎✌️

Here is an example of all rendered meta data you will get from a SeoMaestro field:

<title>Sed dictum eros quis massa semper rutrum. | acme.com</title>
<meta name="description" content="Si lobortis singularis genitus ibidem saluto. Dolore ad nunc, mos accumsan paratus duis suscipit luptatum facilisis macto uxor iaceo quadrum. Demoveo, appellatio elit neque ad commodo ea. Wisi, iaceo, tincidunt at commoveo rusticus et, ludus.">
<meta name="keywords" content="Foo,Bar">
<link rel="canonical" href="https://acme.com/en/about/">
<meta property="og:title" content="Sed dictum eros quis massa semper rutrum.">
<meta property="og:description" content="Si lobortis singularis genitus ibidem saluto. Dolore ad nunc, mos accumsan paratus duis suscipit luptatum facilisis macto uxor iaceo quadrum. Demoveo, appellatio elit neque ad commodo ea. Wisi, iaceo, tincidunt at commoveo rusticus et, ludus.">
<meta property="og:image" content="https://acme.com/site/assets/files/1001/og-image.jpg">
<meta property="og:image:type" content="image/jpg">
<meta property="og:image:width" content="1600">
<meta property="og:image:height" content="1200">
<meta property="og:image:alt" content="Lorem Ipsum">
<meta property="og:type" content="website">
<meta property="og:url" content="https://acme.com/en/about/">
<meta property="og:locale" content="en_EN">
<meta name="twitter:card" content="summary">
<meta name="twitter:creator" content="@schtifu">
<meta name="twitter:site" content="@schtifu">
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
  {
    "@type": "ListItem",
    "position": 1,
    "name": "About",
    "item": "https://acme.com/en/about/"
  }
  ]
}
</script>
<meta name="generator" content="ProcessWire">
<link rel="alternate" href="https://acme.com/en/about/" hreflang="en">
<link rel="alternate" href="https://acme.com/en/about/" hreflang="x-default">
<link rel="alternate" href="https://acme.com/de/ueber/" hreflang="de">
<link rel="alternate" href="https://acme.com/fi/tietoja/" hreflang="fi">
<meta name="google-site-verification" content="google-1234">
<meta name="msvalidate.01" content="bing-1234">

Requirements

Installation

Install the module from the modules directory or with Composer:

composer require wanze/seo-maestro

Configuration

The Seo Maestro module offers the following configuration:

Change sitemap.seomaestro.xml to sitemap.xml once you checked that the sitemap file is correct. The default name reduces the risk to accidentally overwrite an already existing file.

Configure Meta Data and Sitemap Settings for Pages

The meta data and the sitemap configuration of each page is managed with the included Fieldtype. Go ahead and create a new field of type Seo Maestro, a good name for the field is seo 😄.

ℹ️ Edit the field in the context of a template to override any of the default data per template.

XML Sitemap

If enabled, the module hooks after ProcessPageView::finished to generate the XML sitemap after the request has been handled by ProcessWire.

Do not forget to submit the sitemap to Google, either in the Search Console or by specifying the path in a robots.txt file.

⚠ If your installation has lot of pages and the request takes too long to generate the sitemap, or if you run into memory problems, it is better disable the automatic generation. Use the \SeoMaestro\SitemapManager class to create the sitemap on your own, e.g. via CLI script.

Meta Data

Common

Common meta tags that are not managed with the fieldtype, but rendered by default.

Tag Description
<link rel="alternate"> Contains the local url of each active page on multi language sites.
<meta name="generator"> Let anyone know that your site is powered by ProcessWire ❤️

Fieldtype

The following meta data is managed for each page via Seo Maestro field. Meta tags are organized in so called groups.

Group Tags Description
meta title
description
keywords
canonicalUrl
Holds the famous title and description tags that should be optimized for search engines. It is also possible to set a custom canonical URL which by default equals the page's url.
opengraph title
description
image
imageAlt
type
image
locale
siteName
Opengraph meta data is read by facebook and other social networks. By default, title and description inherit the values from the meta group. If an image is specified, the og:image:width, og:image:height and og:image:type tags are included automatically at render time.
twitter card
site
creator
Twitter reads the Opengraph meta data as well, except for a few specific tags managed by this group.
robots noIndex
noFollow
Should robots index a page and follow its links?
structuredData breadcrumb Whether to render structured data (JSON-LD) for breadcrumbs.

Webmaster Tools

If you add the Google and Bing verification codes in the Webmaster Tools section when editing a field, the following meta tags are rendered additionally:

Tag Description
<meta name="google-site-verification"> Contains the Google verification code.
<meta name="msvalidate.01"> Contains the Bing verification code.

Output Meta Tags

Meta tags must be rendered in the <head> region of your templates:

// Render all meta tags, including the common ones.
echo $page->seo;
// or...
echo $page->seo->render();

// Render groups individually, e.g. the opengraph meta data.
echo $page->seo->opengraph->render();

API

The module offers an easy-to-use API to retrieve and modify meta data and sitemap configuration for pages:

// Get a single value.
echo $page->seo->meta->description;

$page->of(false);

// Set values as strings or placeholders to reference the value of another field.
$page->seo->opengraph->description = 'A description for opengraph';
$page->seo->meta->title = '{title}';

// Inherit the Twitter card value from the field configuration.
$page->seo->twitter->card = 'inherit';

// Include the page in the sitemap and bump its priority.
$page->seo->sitemap->include = 1;
$page->seo->sitemap->priority = 0.9;

$page->save();

Values are always set for the current language. Switch the user's language to set values in a different language:

$current = $user->language;

$user->language = $languages->get('de');

$page->of(false);
$page->seo->opengraph->title = 'Hallo Welt';
$page->save();

$user->language = $current;

Available Selectors

The Seo Maestro fieldtype does not support to query meta data with selectors, e.g. seo.meta.title%=foo won't work. All meta data is stored as JSON, allowing to add new data anytime without the need to change the database schema. However, the module stores some useful flags whenever a page is saved, and these flags can be used in selectors:

Examples

Find all pages included in the sitemap:

$pages->find('seo.sitemap_include=1');

Find all pages excluded from the sitemap inheriting all meta and opengraph data:

$pages->find('seo.sitemap_include=0,seo.meta_inherit=1,seo.opengraph_inherit=1');

Hooks

Several hooks are available for developers to customize the behaviour of the module.

___renderMetatags

Add, remove or modify the rendered metatags of a group.

// Remove the description and canonical URL.
$wire->addHookAfter('SeoMaestro::renderMetatags', function (HookEvent $event) {
    $tags = $event->arguments(0);
    $group = $event->arguments(1);

    if ($group === 'meta') {
        unset($tags['description']);
        unset($tags['canonicalUrl']);
        $event->return = $tags;
    }
});

___renderSeoDataValue

Modify the value of meta data after being rendered.

// Add the brand name after the title. 
$wire->addHookAfter('SeoMaestro::renderSeoDataValue', function (HookEvent $event) {
    $group = $event->arguments(0);
    $name = $event->arguments(1);
    $value = $event->arguments(2);

    if ($group === 'meta' && $name === 'title') {
        $event->return = $value . ' | acme.com';
    }
});

___alterSeoDataForm

Customize the inputfields of the form containing the SEO data, e.g. change collapsed states or descriptions.

___sitemapAlwaysExclude

Specify pages that should never appear in the sitemap, regardless of sitemap settings on page level. The 404 page is excluded by default.

$wire->addHookAfter('SeoMaestro::sitemapAlwaysExclude', function (HookEvent $event) {
    $pageArray = $event->arguments(0);
    $pageArray->add($excludedPage);
});

___sitemapItems

Add or modify items in the sitemap.

$item = (new SitemapItem())
    ->set('loc', '/en/my-custom-url')
    ->set('priority', 'custom-priority')
    ->set('changefreq', 'changefreq-custom')
    ->addAlternate('de', '/de/my-custom-url-de');

$wire->addHookAfter('SeoMaestro::sitemapItems', function (HookEvent $event) use ($item) {
    $event->return = array_merge($event->return, [$item]);
});

Running Tests

The module includes PHPUnit based tests cases, located in the ./tests directory.

To run the tests:

cd site/modules/SeoMaestro && vendor/bin/phpunit --bootstrap tests/bootstrap.php tests/src --colors