Kirby SEO - Serp preview field for the panel



To avoid some more errors, change lines 29+30 of site\fields\seo\seo-class.php to:

        if( $raw_title->isNotEmpty() ) {
        } elseif( $page->title()->isNotEmpty() ) {

Possible improvements:

  • Add an input for all “label” lines for the panel at ONE place (e.g. config.php), the default should be “empty”.
  • Add an input for all “help” lines for the panel at ONE place (e.g. config.php), the default should be “empty”.
  • Delete the input/change of the “URL-appendix” within the seo-input to avoid confusion (it is NO new field, it is the same like the page “URI”. This input changes it there too, vice versa!).

With the improvements you can avoid something like the following in every blueprint:

    label: SEO
    type: seo
    help: Two (the first and the last) "Search Engine Optimization" fields. Select <b>each</b> to show the respective input field!



Thanks for your input. I’ve added a fix for your last finding.

What you want is in a simple way not repeat yourself in all the blueprints? In that case I think we can just use the built in Global Field Definitions.

I will add it to the docs how to use the plugin with it. This field will probably be used in the majority of all the blueprints (that are pages) anyway.

At my work I have a new version of the plugin soon finished. I will make sure these changes will be in there as well. That version contains refactoring and some design updates. Want to get a solid base before I add more stuff to it.


Hi @jenstornell nice seeing this awesome plugin taking shape,

But I just got two small thoughts from your gif animation.

I’m not really sure if the panel ships with an char counter somewhere (for constancy), but would it otherwise be possible to move the counters down to the Heading of the field you’re editing, like “SEO Title (75)” when exceeded it could be “SEO Title (<del>124</del>)” or “SEO Title (124!)” - that way the SERP-snippet would look more like the actual Google SERP-snippet again :blush:

Also the empty state for description “No description yet” could be the first 155 chars of a text field if one is present (still without outputting it in the frontend) - an empty description field can actually be more of a feature rather than a missing piece (no desc might be better than a bad desc), as Google then automatically shows and highlights what’s relevant to the search - but filling it with something in its empty state, might make it seem less like a missing piece.

Thank you.


Thanks for your ideas!

I’m not sure. The editable seo title and description are only available when clicking on them. With your suggestion the warnings would be completely hidden until clicking on them. My idea was to spot the warnings right away. Feedback from other people on this would be good.

The other suggestion. You want to fill the empty description in the panel with content from the first field that is of type text. But only in the panel? It could be misleading. The admin user will most likely think that it’s the description on the frontend. Therefor I think it could be a too confusing feature. More feedback are welcome.


Kirby SEO 0.3

I’ve listened to your feedback and release a new version. It’s very much back to basics. It’s much more design in line with how the panel look and work.

See Changelog for information of what is changed.

(The font family is wrong in the GIF, but it’s fixed)


Hi @jenstornell :smiley:

I think the counters fits in much better now - the thing as a whole looks way cleaner and more concise. I love that.

But about the empty-state for description, I’d still think that “No description yet” would be preferred for indication purposes, I’m actually afraid that no one outside this discussion would clearly know where to add the description now :open_mouth:

It could be “No description yet” when a text field either isn’t present or hasen’t yet been filled, on the other hand if text has been filled I still don’t think showing the first bit would be too misleading in the sense that it’s a serp-snippet preview, Shopify actually does it that way.

Default Empty State:

Default Empty State when Editing:

Filled State:


I second @JimmyRittenborg’s statement. The current empty states are bad UX as they don’t suggest that any option is possible.

I think always displaying the text fields by default is the best option for the moment.


@JimmyRittenborg @PaulMorel

In this case with the presentational description, it’s not possible to see if the description is written or if it’s just for demonstration purposes.

Is the description written or just a demo?

Impossible to tell. If I want to set a custom written description on all pages on my site, I need to click on every description to make sure it’s there. Else it’s generrated as empty, even if it shows it’s not.


If this is going to work I think there needs to be some kind of notification. Maybe a bell?

The bell could be clickable to open whatever it reacts on, in this case edit the description.

A more discreet version:

Or some kind of direct message:

What do you think? Does the bell disturb the serp preview too much?

I like the discreet bell most of these three.


I do see what you mean - but it actually is possible to tell em apart by the most likely " …" in the end of the presentational description.

However props for your out of the box thinking with the discreet bell, quite clever and doesn’t disturb the preview too much.

There is however another possibility for this too that might be worth considering, and that is to mimic the tag Google use in their mobile SERPs to tell if a page is mobile friendly, having it say "Missing - ", "Default - ", "Unfilled - " or "Empty - "


I think your idea is really clever! What I like about it is this:

  • It’s just a Google Serp, no other stuff. Still no need for a bell.
  • It’s a part of the description so it’s really natural to click on it to edit.

If no protests comes in, I’ll go with this. I feel like "Empty - " would be the most fitting and simple name for it.


I think it shouldn’t look like something that can be added by Google as well. It should be obvious that this is an info for the panel user not visible in the real field. Maybe a semi transparent overlay containing the word “empty”?!


But how would Google not add it? In my opinion, this component should be considered more an, as close representation of how the page will look like when it show up at the Google SERP and less about showing the “blanks which needs to be filled” as nothing beats the usability of the clear and simple inputs Kirby offers already, this component is an extension and another representation of just that. No props are given by Google for just filling in this field - that only happens if what’s in it is great and correct anyway.


@tobiasweh @JimmyRittenborg @PaulMorel

Now I’ve tried to use the mobile label and it did not go as well as I was hoping for.

  1. The mobile serp have different colors and font sizes. The description color is brighter on the desktop version. It makes it hard to spot any difference between the label and the description in the desktop version. To make them differ I need to fake the label color and make it even brighter. It works ok, but we getting a bit away from the original serp.
  2. The label does not look so good on different languages. In swedish it would be "Tom - ".
  3. The label is not a part of the description on desktop, so it’s a little strange to add it there, especially because the style is different.
  4. It’s not that understandable. Here I agree with @tobiasweh.

Maybe most of the problems above are tiny, but the last one was the one that made me change my mind about this.

Empty overlay

I’m not sure if I like the “Empty” overlay thing. It can feel like noice, something in the way. Something that stresses you.



No overlay, but make the demo description 50% transparent when empty.


Bring back the bell. In this case I’ve moved it to be like a part of the description, which mean a click on the bell is the same surface as a click on the description.

Do you like any one of these two? Or do you have more alternatives?


You have my vote for solution 1, that one is brilliant :ok_hand:


I’d prefer no. 1 too.


Thanks! Then I’ll go with it.

I’m working on the controller thing and will not release anything before that feature is done. I’m almost done but have some ugly bugs to take care of before releasing it.


I’m making some progress. Scroll down for an animated screenshot.


Controllers are used as a kind of fallback if the titles and descriptions are not already set in the panel. They will also be a help in the panel to create custom ones.

There are two types of controllers, template controllers and a site controller.

  1. If a field value is empty it falls back on the template controller.
  2. If the template controller does not exist, it falls back on the site controller.
  3. If the site controller does not exist, it falls back on something else depending on type.

An example of a template or site controller

Might be site/controllers/seo/default.php (template controller) or site/controllers/seo/site.php (site controller).

return function($site, $pages, $page) {
  return [
    'title' => [
      'template' => '{{product}} makes {{category}}',
      'suffix' => ' - {{sitename}}',
      'prefix' => ''
    'description' => [
      'template' => 'We sell {{product}} {{category}}. Welcome to {{sitename}}!',
    'values' => [
        'product' => $page->title(),
        'category' => ( $page->category()->isNotEmpty() ) ? $page->category() : 'shoes',
        'sitename' => ''
  • It works the same way Kirby controllers work.
  • {{keys}} will be replaced with the values from values.
  • Title and descriptions has the same parameters, even if I don’t use suffix etc in description here.
  • Values can be anything, key and value pairs.
  • Title and description share the same values within a controller.

If this is the default.php controller, then the template suffix will fall back to site.php if it has a description suffix.

Controllers in the panel

If you choose to use controllers you can do more than just use it as fallback. You can make it help you with creating titles and descriptions in the panel.

The demo below is based on the controller above.

The GIF colors are a little off and it’s a bit blurry, but you can probably get an idea of how it works.

If for example your category is changed, the title and description will automatically reflect that if you use {{category}} in this case.


Like it? Don’t like it? Why? Why not? Want to change anything?


Now I’ve released it. Version 0.4. Major update!

Add issues on Github if you find something strange.


I just started an seo archive field. Here is a teaser of that:

It’s not possible to add admin pages to the panel. Instead I added admin/seo as new pages with an archive field in a blueprint like this:

title: Seo archive
pages: false
files: false
    type: seoarchive

I list the result of all the pages as close to the google search result as possible. To edit a page, click on it.


Improvents made to the seo archive field:

  • Pagination by using the built in limit feature.
  • Description fallback now also work in the seo archive.


This is now my recommended blueprint. No reason to show pages, files or preview.

title: Seo Archive
  hide: true
  limit: 3
    - error
    - some/child/page
files: false
  preview: false
    type: seoarchive