In my new role as a WooCommerce Developer I've been spending a good chunk of time auditing 3rd party extensions. One of the surprising parts about the audit process is seeing where developers put their settings. Some developers put them under Settings, some put them under a custom menu item, and some just shimmy it in wherever they can.
If you're building a WooCommerce extension the easiest thing you can do to improve your UI is to put all WooCommerce settings where users can find them – on a new WooCommerce settings tab. Sounds pretty easy but you'd be surprised how many people don't do that.
TLDR: example code at the bottom.
Adding a shiny new WooCommerce settings tab only takes three small steps:
- Add your new tab to the array of existing tabs
- Create an array of settings and pass them to the output function
- Pass that same array to the save settings function
1 – Add a New WooCommerce Settings Tab
The first thing you have to do is add a new settings tab. This is actually pretty easy. You just need to add one extra array item to the woocommerce_settings_tabs_array
filter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class WC_Settings_Tab_Demo { | |
public static function init() { | |
add_filter( 'woocommerce_settings_tabs_array', __CLASS__ . '::add_settings_tab', 50 ); | |
} | |
public static function add_settings_tab( $settings_tabs ) { | |
$settings_tabs['settings_tab_demo'] = __( 'Settings Demo Tab', 'woocommerce-settings-tab-demo' ); | |
return $settings_tabs; | |
} | |
} | |
WC_Settings_Tab_Demo::init(); |
2 – Add Your Settings to the Settings Tab
That creates a brand new tab for you to use. Now you need to populate it with settings. There's a handy function, woocommerce_admin_fields
, that you can call and pass in an array of settings. There's a trick here that you can use to make the next step easier. Create one function that only returns your array of settings and then another function that calls the woocommerce_admin_fields
function. You'll thank me in the next step.
You'll see below that I'm passing in four “settings”. Two of them are actual settings, one it a title, and one is a section end. You'll want to look through output_fields()
in class-wc-admin-settings.php to see all of the available options.
It should look something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
add_action( 'woocommerce_settings_tabs_settings_tab_demo', 'settings_tab' ); | |
function settings_tab() { | |
woocommerce_admin_fields( get_settings() ); | |
} | |
function get_settings() { | |
$settings = array( | |
'section_title' => array( | |
'name' => __( 'Section Title', 'woocommerce-settings-tab-demo' ), | |
'type' => 'title', | |
'desc' => '', | |
'id' => 'wc_settings_tab_demo_section_title' | |
), | |
'title' => array( | |
'name' => __( 'Title', 'woocommerce-settings-tab-demo' ), | |
'type' => 'text', | |
'desc' => __( 'This is some helper text', 'woocommerce-settings-tab-demo' ), | |
'id' => 'wc_settings_tab_demo_title' | |
), | |
'description' => array( | |
'name' => __( 'Description', 'woocommerce-settings-tab-demo' ), | |
'type' => 'textarea', | |
'desc' => __( 'This is a paragraph describing the setting. Lorem ipsum yadda yadda yadda. Lorem ipsum yadda yadda yadda. Lorem ipsum yadda yadda yadda. Lorem ipsum yadda yadda yadda.', 'woocommerce-settings-tab-demo' ), | |
'id' => 'wc_settings_tab_demo_description' | |
), | |
'section_end' => array( | |
'type' => 'sectionend', | |
'id' => 'wc_settings_tab_demo_section_end' | |
) | |
); | |
return apply_filters( 'wc_settings_tab_demo_settings', $settings ); | |
} |
3 – Save Your Settings
So by now you should be able to see your settings on your brand new tab. But if you press the save button you'll notice nothing happens. You still need to hook up the save functionality. Hopefully you took my advice in the last section and you created a separate function which returns an array of settings you just need to pass that exact same array into a save function, woocommerce_update_options()
.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
add_action( 'woocommerce_update_options_settings_tab_demo', 'update_settings' ); | |
function update_settings() { | |
woocommerce_update_options( get_settings() ); | |
} |
Wrapping it all up
There's really only three steps to this whole process. If you followed along you're all done. Go ahead and replace my dummy settings with your actual settings. I have a complete version here if you had any trouble following along (or if you're lazy and you skipped to the bottom of the page) 🙂
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/ | |
* Plugin Name: WooCommerce Settings Tab Demo | |
* Plugin URI: https://gist.github.com/BFTrick/b5e3afa6f4f83ba2e54a | |
* Description: A plugin demonstrating how to add a WooCommerce settings tab. | |
* Author: Patrick Rauland | |
* Author URI: http://speakinginbytes.com/ | |
* Version: 1.0 | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
*/ | |
class WC_Settings_Tab_Demo { | |
/ | |
* Bootstraps the class and hooks required actions & filters. | |
* | |
*/ | |
public static function init() { | |
add_filter( 'woocommerce_settings_tabs_array', __CLASS__ . '::add_settings_tab', 50 ); | |
add_action( 'woocommerce_settings_tabs_settings_tab_demo', __CLASS__ . '::settings_tab' ); | |
add_action( 'woocommerce_update_options_settings_tab_demo', __CLASS__ . '::update_settings' ); | |
} | |
/ | |
* Add a new settings tab to the WooCommerce settings tabs array. | |
* | |
* @param array $settings_tabs Array of WooCommerce setting tabs & their labels, excluding the Subscription tab. | |
* @return array $settings_tabs Array of WooCommerce setting tabs & their labels, including the Subscription tab. | |
*/ | |
public static function add_settings_tab( $settings_tabs ) { | |
$settings_tabs['settings_tab_demo'] = __( 'Settings Demo Tab', 'woocommerce-settings-tab-demo' ); | |
return $settings_tabs; | |
} | |
/ | |
* Uses the WooCommerce admin fields API to output settings via the @see woocommerce_admin_fields() function. | |
* | |
* @uses woocommerce_admin_fields() | |
* @uses self::get_settings() | |
*/ | |
public static function settings_tab() { | |
woocommerce_admin_fields( self::get_settings() ); | |
} | |
/ | |
* Uses the WooCommerce options API to save settings via the @see woocommerce_update_options() function. | |
* | |
* @uses woocommerce_update_options() | |
* @uses self::get_settings() | |
*/ | |
public static function update_settings() { | |
woocommerce_update_options( self::get_settings() ); | |
} | |
/ | |
* Get all the settings for this plugin for @see woocommerce_admin_fields() function. | |
* | |
* @return array Array of settings for @see woocommerce_admin_fields() function. | |
*/ | |
public static function get_settings() { | |
$settings = array( | |
'section_title' => array( | |
'name' => __( 'Section Title', 'woocommerce-settings-tab-demo' ), | |
'type' => 'title', | |
'desc' => '', | |
'id' => 'wc_settings_tab_demo_section_title' | |
), | |
'title' => array( | |
'name' => __( 'Title', 'woocommerce-settings-tab-demo' ), | |
'type' => 'text', | |
'desc' => __( 'This is some helper text', 'woocommerce-settings-tab-demo' ), | |
'id' => 'wc_settings_tab_demo_title' | |
), | |
'description' => array( | |
'name' => __( 'Description', 'woocommerce-settings-tab-demo' ), | |
'type' => 'textarea', | |
'desc' => __( 'This is a paragraph describing the setting. Lorem ipsum yadda yadda yadda. Lorem ipsum yadda yadda yadda. Lorem ipsum yadda yadda yadda. Lorem ipsum yadda yadda yadda.', 'woocommerce-settings-tab-demo' ), | |
'id' => 'wc_settings_tab_demo_description' | |
), | |
'section_end' => array( | |
'type' => 'sectionend', | |
'id' => 'wc_settings_tab_demo_section_end' | |
) | |
); | |
return apply_filters( 'wc_settings_tab_demo_settings', $settings ); | |
} | |
} | |
WC_Settings_Tab_Demo::init(); |
thanks for the tutorial!
how can i put multiple fields into one line (e.g. address: first name and last name, and in the next line street and street number (need that for define a pickup address …))
You’ll have to dig into the functions that export the markup and create your own setting. There’s an example how to do this using the WooCommerce Integration Class but it will work with the settings class as well.
I added a custom type to your code but not able to merge it back. Here is the gist: https://gist.github.com/neo99/eec01b9df3448ee27ee6
Please feel free to add it back to your gist.
Thanks for the code sample! With a quick glance it looks good. I’d rather not merge it into my code sample. I don’t think every user needs a custom setting and would rather not confuse them. I’ll just leave your link here and they can find it that way. 🙂
Hi Patrick,
Thank you so much for this code. Can you tell me how to add sections inside the custom settings tab? I really need that. I have tried different ways but not got that.
Hey Ajay,
Look at the different types of settings. There are settings with a type of title as well as sectionend.
Thanks for the reply. Still I am not getting you. Can you give some dummy code for adding sections inside your plugin code. That will be really appreciable. Thanks
I wish I had the time to write up exactly how to do it – I’d reach out to Codeable. They can write whatever code you need and if you need to customize it it should be pretty understandable.
Yep, adding to the Woo interface makes perfect sense. I almost fell into the trap:
But your post put me right. Cheers \m/
Hey, great post! I am pretty new to PHP and WordPress development and I am just running a few exercises… I don’t really understand what is the right approach to get the settings and actively use them for a plugin.
Hi Mirko – well if you’re altering the way WooCommerce works I’d suggest using the code snippet in this post. 🙂
If you’re creating a whole new plugin it’s pretty common to create your own plugin settings page. To do this you can use the WordPress Settings API. It isn’t the friendliest API so I’d find lots of examples. It’s a bit of a slow learning curve but I think it’s better to go this route rather than use a plugin settings generator which create a lot of garbage code.
Hi Patrick,
the first one, I am trying to add a simple function to WooCommerce.
But for the sake of my “learning process” I was trying to understand how to load and use the options. Should I add my function inside the same class and refer to variables such as:
$this->wc_settings_tab_demo_description
?
Hi Mirko – I can’t write up sample code snippet right now. What I would do is look through WooCommerce code and see how WooCommerce loads settings when it needs them.
Hi Patrick, sure! Appreciate your replies anyway!
Cheers,
Mirko
Hello, i liked your tutorial and i just wanted to ask , we do you use static class in this example ? does that make some difference from the regular way of instantiating the class
thx
Good question! I sometimes find it quite useful to have static functions for calling from one class to another but you don’t have to. Just something I prefer. 🙂
I saw different implementation, is there any difference between
$settings = array(
'section_title' => array(
and (without section_title key)
$settings = array(
array(
What is the difference between this API and functions
init_form_fields()
andinit_settings()
which are used for Payment and Shipping Gateways? Or it is the same Settings API (options are saved into serialized groups in this case)?Hi Pavel,
I haven’t tried doing it without the
section_title
. What is the difference? Please do share. 🙂For the Shipping & Payment Gateway APIs I would follow those tutorials. You aren’t creating your own settings page. You’re following a specific set of instructions so that WooCommerce will create it for you.
I hope that helps! 🙂
Hi Patrick,
How would this be modified to add a setting to a sub-section of a tab? I’m seeing conflicting approaches in both the official Woo docs and various other articles and I wondered what your take was?
Hi Dave & Patrick,
Dave, can you point to the official WooCommerce docs that recommend where we should put out plugin settings. I too am not sure where is best/right.
Thanks for the great tutorial Patrick. I am also interested in your take on whether to use a Tab, or subsection, as in Dave’s question.
One of my plugins has only 2 settings – https://codecanyon.net/item/shop-as-customer-for-woocommerce/7043722 – it seems excessive to create my own tab for 2 options.
I’m working on a plugin and I need to grab an API URL in various places – like a .php file that is receiving a form via AJAX.
How do I get the value stored in the settings?
If I just put global $woocommerce, then var_dump($woocommerce); — I can see the setting I want buried waayyy deep in the object.
Is there ‘normal’ / ‘best practice’ way to get a value from a stored setting?
Thanks!
Hi there,
thanks for the nice guide. I have just noticed that the new tab does not appear on any site that is not the main one on a WP network. Can you think of any reason?
Thanks
Can you please let me know where are the options saved into the database.
So if I create my own tab like this:
$settings_tabs[‘my_own_tab’] =
I have a question about this line… is this woocommerce filter or a custom filter?
return apply_filters( ‘wc_settings_tab_demo_settings’, $settings );
Would I just change this to ‘wc_my_own_tab_settings’?
Thanks
Anyone having a problem after Woocommece 4.2 version?
PHP Notice: Undefined index: id in /public_html/wp-content/plugins/woocommerce/packages/woocommerce-admin/src/Loader.php on line 865
Best regards!
Hi, and thanks for the tutorial.
I would suggest to remove array key, when adding a section title / fields or section end inside $settings array.
Example:
‘section_title’ => array(
‘name’ => __( ‘Section Title’, ‘woocommerce-settings-tab-demo’ ),
‘type’ => ‘title’,
‘desc’ => ”,
‘id’ => ‘wc_settings_tab_demo_section_title’
),
Should be just :
array(
‘name’ => __( ‘Section Title’, ‘woocommerce-settings-tab-demo’ ),
‘type’ => ‘title’,
‘desc’ => ”,
‘id’ => ‘wc_settings_tab_demo_section_title’
),
The reason is, when I have tried to add multiple sections, they become sorted randomly, and even “Save changes” button could appear somewhere in the middle of the page.
Looking at WooCommerce source as reference ( woocommerce/includes/admin/settings/class-wc-settings-accounts.php ), in fact there is also no array keys.
How Can i add multiple sections inside this new tab?
Hi Patrick,
is it possible to set up some capability for the new added setting tab, so that will only allow some specific role to reach this tab? if it is possible , how to do it ? thanks.