├── .gitignore
├── README.md
├── blueprints
├── fields
│ └── meta.yml
└── tabs
│ ├── contact.yml
│ └── meta.yml
├── composer.json
├── index.php
└── snippets
├── favicon.php
└── meta.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | composer.lock
3 | vendor
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kirby 3 SEO Plugin
2 |
3 | A small plugin for generating meta data using shared controllers and field data. Also creates Facebook Opengraph and Twitter social sharing information.
4 |
5 | Using Kirby 4? a version of the plugin is available [here - kirby4-seo](https://github.com/HashandSalt/kirby4-seo)
6 |
7 | ## Installation
8 |
9 | ### Manual
10 |
11 | To use this plugin, place all the files in `site/plugins/kirby3-seo`.
12 |
13 | ### Composer
14 |
15 | ```
16 | composer require hashandsalt/kirby3-seo
17 | ```
18 | ****
19 |
20 | ## Commerical Usage
21 |
22 | This plugin is free but if you use it in a commercial project please consider to
23 | - [make a donation 🍻](https://paypal.me/hashandsalt?locale.x=en_GB) or
24 | - [buy a Kirby license using this affiliate link](https://a.paddle.com/v2/click/1129/36141?link=1170)
25 |
26 | ****
27 |
28 | ## Usage
29 |
30 | After installing the plugin, setup controllers to bring in the shared SEO controller into each of your template
31 | controllers.
32 |
33 | The bare minimum controller looks like this:
34 |
35 | ```
36 | controller('seo' , compact('page', 'site', 'kirby'));
42 |
43 | return $seo;
44 |
45 | };
46 | ```
47 |
48 | To override any of the values, you can do this inside your controller. For example, to change the format of the meta title, you could do this:
49 |
50 | ```
51 | controller('seo' , compact('page', 'site', 'kirby'));
57 |
58 | // Override Meta Title
59 | $metatitle = $page->seotitle().' | '.$site->title();
60 |
61 | $data = compact('metatitle');
62 |
63 | return a::merge($seo, $data);
64 |
65 | };
66 |
67 | ```
68 |
69 | Additionally, you need to populate the pages with information that is needed for the meta tags to be filled out correctly. The plugin contains blueprints for this and are meant to be used as tabs in your pages:
70 |
71 | ```
72 | title: Default
73 |
74 | tabs:
75 |
76 | # SEO META
77 | meta: tabs/seo/meta
78 |
79 | ```
80 |
81 | In the `site.yml` also setup the contact tab which will capture social media account information.
82 |
83 | ```
84 | title: Site
85 |
86 | tabs:
87 |
88 | # Contact
89 | contact: tabs/seo/contact
90 | ```
91 |
92 | Finally, output the meta tags in your templates with the following snippet.
93 |
94 | ```
95 | = snippet('seo/meta') ?>
96 | ```
97 |
98 | For convenience the plugin also contains a favicon snippet:
99 |
100 | ```
101 | = snippet('seo/favicon') ?>
102 | ```
103 |
104 | You can generate the favicons at [this website link](https://realfavicongenerator.net/)
105 |
106 |
107 | ## Generating JSON Schema data
108 |
109 | To generate any kind of schema data, you can use our [Schema plugin](https://github.com/HashandSalt/kirby3-schema) in tandem with this plugin.
110 |
--------------------------------------------------------------------------------
/blueprints/fields/meta.yml:
--------------------------------------------------------------------------------
1 | type: group
2 | fields:
3 |
4 | seotitle:
5 | label: SEO Title
6 | type: text
7 | icon: font
8 | width: 1/2
9 | required: true
10 | seotags:
11 | label: Keywords
12 | type: tags
13 | width: 1/2
14 | seometa:
15 | label: Meta Description
16 | type: textarea
17 | size: small
18 | required: true
19 |
--------------------------------------------------------------------------------
/blueprints/tabs/contact.yml:
--------------------------------------------------------------------------------
1 | label: Contact
2 | icon: globe
3 |
4 | fields:
5 | telephone:
6 | label: Telephone
7 | type: tel
8 | width: 1/3
9 | emailaddress:
10 | label: Email Address
11 | type: email
12 | width: 1/3
13 | socialtwitterURL:
14 | label: Twitter
15 | type: url
16 | width: 1/3
17 | twittercreator:
18 | label: Twitter Creator
19 | type: text
20 | width: 1/3
21 | sociallinkedinURL:
22 | label: LinkedIn
23 | type: url
24 | width: 1/3
25 | socialfaceBookURL:
26 | label: Facebook
27 | type: url
28 | width: 1/3
29 | socialinstagramURL:
30 | label: Instagram
31 | type: url
32 | width: 1/3
33 | socialpinterestURL:
34 | label: Pinterest
35 | type: url
36 | width: 1/3
37 | socialyoutubeURL:
38 | label: Youtube
39 | type: url
40 | width: 1/3
41 |
--------------------------------------------------------------------------------
/blueprints/tabs/meta.yml:
--------------------------------------------------------------------------------
1 | label: SEO
2 | icon: search
3 | columns:
4 | # SEO Meta
5 | left:
6 | width: 2/3
7 | sections:
8 |
9 | seocontent:
10 | type: fields
11 | fields:
12 | extends: fields/seo/meta
13 |
14 | # Share Image
15 | right:
16 | width: 1/3
17 | sections:
18 | seomedia:
19 | type: fields
20 | fields:
21 | shareimage:
22 | label: Share Image
23 | type: files
24 | uploads:
25 | template: shot
26 | width: 1/3
27 | max: 1
28 | info: "{{ file.dimensions }}"
29 | image:
30 | ratio: 2/1
31 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hashandsalt/kirby3-seo",
3 | "description": "Kirby 3 - SEO tools",
4 | "type": "kirby-plugin",
5 | "license": "MIT",
6 | "authors": [{
7 | "name": "James Steel",
8 | "email": "hello@hashandsalt.com"
9 | }],
10 |
11 | "require": {
12 | "getkirby/composer-installer": "^1.1"
13 | },
14 | "config": {
15 | "optimize-autoloader": true
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | [
8 | 'seo/meta' => __DIR__ . '/snippets/meta.php',
9 | 'seo/favicon' => __DIR__ . '/snippets/favicon.php'
10 | ],
11 |
12 | 'blueprints' => [
13 | 'tabs/seo/contact' => __DIR__ . '/blueprints/tabs/contact.yml',
14 | 'tabs/seo/meta' => __DIR__ . '/blueprints/tabs/meta.yml',
15 | 'fields/seo/meta' => __DIR__ . '/blueprints/fields/meta.yml'
16 | ],
17 |
18 | 'controllers' => [
19 |
20 | 'seo' => function ($page, $kirby, $site) {
21 | return [
22 |
23 | // Meta
24 | 'metatitle' => $page->title(),
25 | 'metadesc' => $page->seometa(),
26 | 'metakeywords' => $page->seotags(),
27 | 'metarobots' => 'index, follow, noodp',
28 | 'metaurl' => $page->url(),
29 | 'metaimage' => $page->shareimage()->toFile() ? $page->shareimage()->toFile()->crop(1280, 720)->url() : ' ',
30 |
31 | // Facebook Meta
32 | 'metafbtype' => 'website',
33 | 'metafbsitename' => $site->title(),
34 | 'metafblocale' => 'en_GB',
35 |
36 | // Twitter Meta
37 | 'metatwcard' => 'summary_large_image',
38 | 'metatwsite' => $site->socialtwitterurl()->isNotEmpty() ? $site->socialtwitterurl() : ' ',
39 | 'metatwcreator' => $site->twittercreator()->isNotEmpty() ? $site->twittercreator() : ' ',
40 |
41 | ];
42 | }
43 | ]
44 | ]);
45 |
--------------------------------------------------------------------------------
/snippets/favicon.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/snippets/meta.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | = Html::tag('title', [$metatitle]).PHP_EOL ?>
4 | = Html::tag('meta', null, ["name" => "description", "content" => $metadesc]).PHP_EOL ?>
5 | = Html::tag('meta', null, ["name" => "keywords", "content" => $metakeywords]).PHP_EOL ?>
6 |
7 | = Html::tag('meta', null, ["property" => "og:title", "content" => $metatitle]).PHP_EOL ?>
8 | = Html::tag('meta', null, ["property" => "og:type", "content" => $metafbtype]).PHP_EOL ?>
9 | = Html::tag('meta', null, ["property" => "og:site_name", "content" => $metafbsitename]).PHP_EOL ?>
10 | = Html::tag('meta', null, ["property" => "og:url", "content" => $metaurl]).PHP_EOL ?>
11 | = Html::tag('meta', null, ["property" => "og:image", "content" => $metaimage ]).PHP_EOL ?>
12 | = Html::tag('meta', null, ["property" => "og:description", "content" => $metadesc]).PHP_EOL ?>
13 | = Html::tag('meta', null, ["property" => "og:locale", "content" => $metafblocale]).PHP_EOL ?>
14 |
15 | = Html::tag('meta', null, ["name" => "twitter:title", "content" => $metatitle]).PHP_EOL ?>
16 | = Html::tag('meta', null, ["name" => "twitter:card", "content" => $metatwcard]).PHP_EOL ?>
17 | = Html::tag('meta', null, ["name" => "twitter:site", "content" => $metatwsite]).PHP_EOL ?>
18 | = Html::tag('meta', null, ["name" => "twitter:creator", "content" => $metatwcreator]).PHP_EOL ?>
19 | = Html::tag('meta', null, ["name" => "twitter:image", "content" => $metaimage ]).PHP_EOL ?>
20 | = Html::tag('meta', null, ["name" => "twitter:url", "content" => $metaurl]).PHP_EOL ?>
21 | = Html::tag('meta', null, ["name" => "twitter:description", "content" => $metadesc]).PHP_EOL ?>
22 |
23 | = Html::tag('meta', null, ["name" => "robots", "content" => $metarobots]).PHP_EOL ?>
24 |
--------------------------------------------------------------------------------