Forms for Page Meta-Tabs
Do you need a special meta-information for pages in your theme? Or do you want to create a SEO-tab for each page? No problem, because you can add your own meta-fields or even your own meta-tabs with a plugin and with the help of vue.js.
#Add Fields to a Tab
By default, each page has a meta-tab called "meta". To add a new field to that tab, simply create a plugin or a theme with a new YAML definition, that starts with the keyword metatabs
followed by the name of the tab meta
like this:
name: Example Plugin
version: 1.0.0
description: Add a short description
author: Firstname Lastname
homepage: http://your-website.net
licence: MIT
metatabs:
meta:
fields:
myfield:
type: select
label: Select an Option
options:
green: Green
blue: Blue
This will add a new select-field to the existing tab "meta".
#Store and Use Meta-Information
Similar to the famous "frontmatter", Typemill can store any kind of meta-information for a each content page. Different to frontmatter, Typemill does not store the meta-information in the markdown-file, but it creates a separate yaml-file to keep the markdown-file clean and readable.
Typemill uses some standard-meta-information like the title, the description and the author. But you can also add your own fields to the meta-tab and use all meta-information in your twig-templates with the variable metatabs
like this:
{{ metatabs.meta.myfield }}
You can also access the information in your plugin with the event onMetaLoaded
like this:
<?php
namespace Plugins\Example;
use \Typemill\Plugin;
class Example extends Plugin
{
public static function getSubscribedEvents()
{
return array(
'onMetaLoaded' => 'onMetaLoaded'
);
}
public function onMetaLoaded($meta)
{
$meta = $meta->getData();
if($meta['meta']['myfield'] == "green")
{
# make something green here
}
}
#Create a New Meta-Tab
With a plugin, you can also create a new meta-tab for pages. Just add a new yaml-configuration to your plugin and give your meta-tab a name like this:
name: Example Plugin
version: 1.0.0
description: Add a short description
author: Firstname Lastname
homepage: http://your-website.net
licence: MIT
metatabs:
mytab:
fields:
myfield:
type: text
label: Add some text
If you activate the plugin, then you will already see a new tab called "mytab" for each page.
However, if you click on the tab, you will not see any forms yet. The reason is quite simple: Different to forms for plugins, themes or public pages, the forms for meta-tabs are rendered with Vue.js and not with PHP. In order to render the forms, you have to activate the vue form generator. This is done with a simple copy & paste.
#Add the Vue Component
You can activate the vue form-generator in your plugin with a simple script (a vue-component). In the first step we add that script to the editor like this:
<?php
namespace Plugins\Example;
use \Typemill\Plugin;
class Example extends Plugin
{
public static function getSubscribedEvents()
{
return array(
'onTwigLoaded' => 'onTwigLoaded'
'onMetaLoaded' => 'onMetaLoaded'
);
}
public function onTwigLoaded()
{
$this->addEditorJS('/example/js/editor.js');
}
public function onMetaLoaded($meta)
{
$meta = $meta->getData();
# do something with the fields:
$myTabInformation = $meta['mytab'];
}
}
We used the event onTwigLoaded
to add the script, but you can also use other events if you want.
In the next step we will create the script. The script is a simple vue-component that looks always like this:
Vue.component('tab-mytab', {
props: ['saved', 'errors', 'formdata', 'schema', 'userroles'],
template: '<section><form>' +
'<div v-for="(field, index) in schema.fields">' +
'<fieldset v-if="field.type == \'fieldset\'" class="fs-formbuilder"><legend>{{field.legend}}</legend>' +
'<component v-for="(subfield, index) in field.fields "' +
':key="index"' +
':is="selectComponent(subfield)"' +
':errors="errors"' +
':name="index"' +
':userroles="userroles"' +
'v-model="formdata[index]"' +
'v-bind="subfield">' +
'</component>' +
'</fieldset>' +
'<component v-else' +
':key="index"' +
':is="selectComponent(field)"' +
':errors="errors"' +
':name="index"' +
':userroles="userroles"' +
'v-model="formdata[index]"' +
'v-bind="field">' +
'</component>' +
'</div>' +
'<div v-if="saved" class="metasubmit"><div class="metaSuccess">Saved successfully</div></div>' +
'<div v-if="errors" class="metasubmit"><div class="metaErrors">Please correct the errors above</div></div>' +
'<div class="metasubmit"><input type="submit" @click.prevent="saveInput" value="save"></input></div>' +
'</form></section>',
methods: {
selectComponent: function(field)
{
return 'component-'+field.type;
},
saveInput: function()
{
this.$emit('saveform');
},
}
})
You can simply copy and paste this component, because the vue-component will always look the same. Just change the name of the component Vue.component('tab-mytab', {})
to the name of your tab starting with the prefix "tab-". Please use an unique name for your tab, because there might be conflicts if another plugin uses the same name for a tab.
This is what the vue component does:
- It loops over the fields that you defined in your YAML file.
- It dynamically adds the field component according to the type of each field.
- It binds all neccessary data like the field-definitions, the errors, the name of the field and so on.
- It adds a save button and messages for success and error.
If you want to know how it works in detail, then check the file vue-meta.js
in the folder system/author/js
.
#Extend the Vue Component
The vue-component above just renders the forms and adds a store-button. If you are a vue-developer, then you can do much more and extend the vue-component with all kind of functionalities. You can create whole applications that run in a tab. If you want to see an example, then download the eBook plugin and check the tab. You will see a highly complex application that runs in several sub-tabs and generates eBooks from Typemill websites.
#Limitations
The meta-tabs are flexible as hell, but the actual vue-form-builder has some limitations compared to public forms or to configuration-forms for plugins and themes:
- You cannot add text with the field-type paragraph.
- You cannot use the help text.
- You can use attributes like required or pattern in your yaml-definition. They are used for the backend validation, but they have no effect in the frontend.