Set tabs in settings on Plugin I would like to add tabs in setting page in my plugin. I have the following code in /[myplugin]/templates/_setting.html. However, the tabs do not show up, does anyone have any sample code to set up the tabs? Thanks

{% import "_includes/forms" as forms %}

{% set tabs = {
customer: { label: "Customer"|t, url: url('emailUser/_settings') },
veterinarian:    { label: "Veterinarian"|t, url: url('emailUser/_vetSettings') }
} %}

{{ forms.textField({
label: "Customer Account Creation Confirmation Subject"|t,
instructions: "Customer Account Creation Confirmation Subject" |t,
name: 'custAccountCreationSubject',
value: settings.custAccountCreationSubject,
})}}

{{ forms.textareaField({
label: "Customer Account Creation Confirmation Message"|t,
instructions: "Customer email message when customer register" |t,
name: 'custAccountCreation',
value: settings.custAccountCreation,
rows:10,
})}}


In myplugin.php

public function getSettingsHtml()
{
    return craft()-&gt;templates-&gt;render('emailuser/_settings',array(
                'settings'=&gt;$this-&gt;getSettings()
    ));
}
Here’s a simple plugin with two tabs and two fields, one field per tab. This plugin was generated on https://pluginfactory.io/. It’s a great starting point to get the plugin scaffolding set up. After that I added the code that I’ve included below to get it to work.

It should give you something like the following screenshot for the first tab:



and for the second tab it should look similar to this:



Folder Structure

[-] craft
   [-] plugins
      [-] myplugin
         [-] controllers
            |-- MyPlugin_TabOneController.php
            |-- MyPlugin_TabTwoController.php
         [+] resources
         [+] services
         [-] templates
            [-] _layouts
               |-- cp.twig
            [-] tabOne
               |-- _index.twig
            [-] tabTwo
               |-- _index.twig
         [+] translations
         [+] variables
         |-- MyPluginPlugin.php




myplugin/MyPluginPlugin.php

I'm only highlighting the functions that were necessary for the plugins to show up. Add or adjust them as needed.

...

public function registerCpRoutes()
{
    return array(
        'myplugin' =&gt; ['action' =&gt; "myPlugin/tabOne/index"],
        'myplugin/additional-settings' =&gt; ['action' =&gt; "myPlugin/tabTwo/index"],
        /**
         * Each 'action' relates to a controller in your plugin.
         * The names of your controller and these action must match.
         */
    );
}

protected function defineSettings()
{
    return array(
        'someSetting' =&gt; array(AttributeType::String, 'label' =&gt; 'Some Setting', 'default' =&gt; ''),
        'additionalSetting' =&gt; array(AttributeType::String, 'label' =&gt; 'Some Additional Setting', 'default' =&gt; ''),
        /*...more settings here as needed...*/
    );
}

public function getSettingsHtml()
{
   return craft()-&gt;templates-&gt;render('myplugin/MyPlugin_Settings', array(
       'settings' =&gt; $this-&gt;getSettings()
   ));
}

public function getSettingsUrl()
{
    return 'myplugin';
    /* This must be the same as the first segment in your cpRoutes. */
}

...




myplugin/controllers/MyPlugin_TabOneController.php

namespace Craft;

class MyPlugin_TabOneController extends BaseController
{

    /**
     * @var    bool|array Allows anonymous access to this controller's actions.
     * @access protected
     */
    protected $allowAnonymous = array('actionIndex',
        );

    /**
     */
    public function actionIndex()
    {
        $settings = craft()-&gt;plugins-&gt;getPlugin('myPlugin')-&gt;getSettings();
        $this-&gt;renderTemplate('myplugin/tabOne/_index', array(
            'settings' =&gt; $settings,
        ));
        /**
         * The path above is to your templates folder in your plugin.
         */
    }
}




myplugin/controllers/MyPlugin_TabTwoController.php

namespace Craft;

class MyPlugin_TabTwoController extends BaseController
{

    /**
     * @var    bool|array Allows anonymous access to this controller's actions.
     * @access protected
     */
    protected $allowAnonymous = array('actionIndex',
        );

    /**
     */
    public function actionIndex()
    {
        $settings = craft()-&gt;plugins-&gt;getPlugin('myPlugin')-&gt;getSettings();
        $this-&gt;renderTemplate('myplugin/tabTwo/_index', array(
            'settings' =&gt; $settings,
        ));
        /**
         * The path above is to your templates folder in your plugin.
         */
    }
}




myplugin/templates/_layouts/cp.twig

It’s not necessary to break out the templates like I have here but it does help to keep from repeating your self in the templates, especially if you have several tabs.

{% extends "_layouts/cp" %}
{% import "_includes/forms" as forms %}

{% includeCssResource "myplugin/css/Myplugin_Style.css" %}
{% includeJsResource "myplugin/js/Myplugin_Script.js" %}

{% set title = 'My Plugin' %}

{% set tabs = {
    settings: { label: "Settings"|t, url: url('myplugin') },
    additionalSettings: { label: "Additional Settings"|t, url: url('myplugin/additional-settings') },
} %}




myplugin/templates/tabOne/_index.twig

The data-saveshortcut attribute on the form will allow you to use the keyboard shortcut to save your plugin’s settings by using ⌘ + S on a Mac. I’m assuming that Ctrl + S works on Windows although I haven’t tried it.

{% extends "myplugin/_layouts/cp" %}
{% import "_includes/forms" as forms %}

{% set selectedTab = 'settings' %}

{% set content %}

    &lt;h2&gt;Settings&lt;/h2&gt;

    &lt;form method="post" action="" accept-charset="UTF-8" data-saveshortcut data-confirm-unload&gt;

        {{ getCsrfInput() }}

        &lt;input type="hidden" name="action" value="plugins/savePluginSettings"&gt;
        &lt;input type="hidden" name="pluginClass" value="MyPlugin"&gt;
        &lt;input type="hidden" name="redirect" value="myplugin"&gt;

        {{ forms.textField({
            label: 'Some Setting',
            instructions: 'Enter some setting here.',
            id: 'settings-someSetting',
            name: 'settings[someSetting]', 
            value: settings['someSetting']})
        }}

        &lt;div class="buttons"&gt;
            &lt;input class="btn submit" type="submit" value="{{ 'Save'|t }}"&gt;
        &lt;/div&gt;

    &lt;/form&gt;

{% endset %}




myplugin/templates/tabOne/_index.twig

Notice that you’ll need to set the selectedTab in each template for the tabs to work correctly. This should match one of your keys that was set in the tabs variable in the myplugin/templates/_layouts/cp.twig. Also the hidden redirect input in the form should be set to wherever you want to it end up. I noticed that it felt the best when it went back to the original page and it showed the saved values.

{% extends "myplugin/_layouts/cp" %}
{% import "_includes/forms" as forms %}

{% set selectedTab = 'additionalSettings' %}

{% set content %}

    &lt;h2&gt;Additional Settings&lt;/h2&gt;

    &lt;form method="post" action="" accept-charset="UTF-8" data-saveshortcut data-confirm-unload&gt;

        {{ getCsrfInput() }}

        &lt;input type="hidden" name="action" value="plugins/savePluginSettings"&gt;
        &lt;input type="hidden" name="pluginClass" value="MyPlugin"&gt;
        &lt;input type="hidden" name="redirect" value="myplugin/additional-settings"&gt;

        {{ forms.textField({
            label: 'Some Additional Setting',
            instructions: 'Enter some setting here.',
            id: 'settings-additionalSetting',
            name: 'settings[additionalSetting]', 
            value: settings['additionalSetting']})
        }}

        &lt;div class="buttons"&gt;
            &lt;input class="btn submit" type="submit" value="{{ 'Save'|t }}"&gt;
        &lt;/div&gt;

    &lt;/form&gt;

{% endset %}


That should do it!