Using Kirby SEO Plugin, the email contact form example doesn't work

So I’m using the SEO Plugin
and if add the controllers example from here;

it seems to conflict with the SEO Plugin giving me

“Undefined variable: metatitle”

I’ve tried changing $data to $formdata to see if that variable being used twice was the problem, however it didn’t help


Please always post a link to the plugin in questions, there is often more than one.


See GitHub - HashandSalt/kirby3-seo: A plugin for generating SEO meta tags

You are supposed to integrate the seo controller into your dedicated controllers.

I’m not sure what you mean by dedicated controllers?

I’m just reading over the controllers/shared controllers docs, but I’m still not grasping what I need to do.

I currently have


return function ($page, $kirby, $site) {

  // Meta
  $seo = $kirby->controller('seo' , compact('page', 'site', 'kirby'));

  // Override Meta Title
  $metatitle = $page->seotitle().' | '.$site->title();

  $data = compact('metatitle');

  return a::merge($seo, $data);


in my site/controllers/site.php, is this correct as I want to use it on all pages?

Yes, that looks ok, but you don’t use a dedicated controller for the contact form, you would have to merge the data into this site controller as well. Not so sure this makes sense.

in the form example it says to put the controller code in ‘/site/controllers/contact.php’, is this not a “dedicated” controller?

It’s the first time I’ve heard the term “dedicated” being used sorry for my lack of knowledge.

Yes, that is the controller for the contact.php template ( I just call it dedicated, sorry for the confusion).

are you able to tell me how to do this? I am totally lost

This should work:

return function($kirby, $pages, $page) {

    $alert = null;

    if($kirby->request()->is('POST') && get('submit')) {

        // check the honeypot
        if(empty(get('website')) === false) {

        $data = [
            'name'  => get('name'),
            'email' => get('email'),
            'text'  => get('text')

        $rules = [
            'name'  => ['required', 'minLength' => 3],
            'email' => ['required', 'email'],
            'text'  => ['required', 'minLength' => 3, 'maxLength' => 3000],

        $messages = [
            'name'  => 'Please enter a valid name',
            'email' => 'Please enter a valid email address',
            'text'  => 'Please enter a text between 3 and 3000 characters'

        // some of the data is invalid
        if($invalid = invalid($data, $rules, $messages)) {
            $alert = $invalid;

            // the data is fine, let's send the email
        } else {
            try {
                    'template' => 'email',
                    'from'     => '',
                    'replyTo'  => $data['email'],
                    'to'       => '',
                    'subject'  => esc($data['name']) . ' sent you a message from your contact form',
                    'data'     => [
                        'text'   => esc($data['text']),
                        'sender' => esc($data['name'])

            } catch (Exception $error) {
                    $alert['error'] = 'The form could not be sent: <strong>' . $error->getMessage() . '</strong>';
                    $alert['error'] = 'The form could not be sent!';

            // no exception occurred, let's send a success message
            if (empty($alert) === true) {
                $success = 'Your message has been sent, thank you. We will get back to you soon!';
                $data = [];

    // Meta
  $seo = $kirby->controller('seo' , compact('page', 'site', 'kirby'));

  // Override Meta Title
  $metatitle = $page->seotitle().' | '.$site->title();

  $data = [
    'metatitle' => $metatitle,
    'alert'       => $alert,
    'data'       => $data ?? false,
    'success' => $success ?? false

  return a::merge($seo, $data);

So I’ve deleted all content of the /controllers/contact.php, and added that code to my /controllers/site.php, and I am getting “compact(): Undefined variable: site”

(I am trying to read through and understand what is going on and see if I can do anything myself before asking you, sorry to keep having to ask you to solve everything for me :upside_down_face:)

Controllers should match the template name. If the controller is for pages using blog.php template then your corresponding controller should be also called blog.php in the controllers folder.

And you shouldnt have one called site.php.

I thought putting the SEO bare minimum to get the plugin working code in the site.php would be appropriate as I want it to work on all pages? And then just have the contact.php one with the controller relevant to the form that will only be on that page?

You need a matching pair of templates and controllers and import the SEO controller into them each.

Have a look here, its my boilerplate, and has the SEO plugin wired in.

site.php is not a shared controller but a default/fallback one. If you want to actually use it as a global/shared controller you have to take a few extra steps. Shared Controllers | Kirby CMS

The code I posted above was supposed to go into the contact.php controller, not the site.php controller.

I don’t know, I’ve been trying for 3 hours now still can’t get it to work, I have tried your code in controllers/contact.php and it says “compact(): Undefined variable: site” really not sure what I’m doing wrong

Oh, ok, you have to include $site into the first line of the controller

return function($kirby, $site, $pages, $page) {
1 Like