Ask SkyVerge

This question comes in from blog reader Wilgert (thanks Wilgert!):

could you help me find some simple code to add a custom option field to the general settings tab of the woocommerce admin area? Trying to avoid re-inventing the wheel here.

Well, this may be more than you bargained for, but here we go! The WooCommerce settings can be found under the menu item WooCommerce > Settings and look like so:

WooCommerce Settings General

Like a lot of WooCommerce these settings can be customized thanks to a variety of actions and filters. For the main settings tabs there are 7 important filters to consider:

  • woocommerce_general_settings
  • woocommerce_catalog_settings
  • woocommerce_page_settings
  • woocommerce_inventory_settings
  • woocommerce_tax_settings
  • woocommerce_shipping_settings
  • woocommerce_payment_gateways_settings
  • woocommerce_email_settings

As you can see, one for each of the major tabs, excluding the final “Integration” tab, which is handled elsewhere.

Each of those filters accepts and returns the same nested array data structure, which describes the options and headings shown on the Settings tabs, allowing you easily modify, remove and even add your own custom settings (and even whole new sections of settings). Here’s an example snippet showing some of the common types of settings fields: a dropdown, a text input and a checkbox:

array(
  array(
    'name' => __( 'Pricing Options', 'woocommerce' ),
    'type' => 'title',
    'desc' => __('The following options affect how prices are displayed on the frontend.', 'woocommerce'),
    'id'   => 'pricing_options'
  ),

  array(
    'name'    => __( 'Currency Position', 'woocommerce' ),
    'desc'    => __( 'This controls the position of the currency symbol.', 'woocommerce' ),
    'id'      => 'woocommerce_currency_pos',
    'css'     => 'min-width:150px;',
    'std'     => 'left', // WooCommerce < 2.0
    'default' => 'left', // WooCommerce >= 2.0
    'type'    => 'select',
    'options' => array(
      'left'        => __( 'Left', 'woocommerce' ),
      'right'       => __( 'Right', 'woocommerce' ),
      'left_space'  => __( 'Left (with space)', 'woocommerce' ),
      'right_space' => __( 'Right (with space)', 'woocommerce' )
    ),
    'desc_tip' =>  true,
  ),

  array(
    'name'     => __( 'Thousand separator', 'woocommerce' ),
    'desc'     => __( 'This sets the thousand separator of displayed prices.', 'woocommerce' ),
    'id'       => 'woocommerce_price_thousand_sep',
    'css'      => 'width:30px;',
    'std'      => ',', // WooCommerce < 2.0
    'default'  => ',', // WooCommerce >= 2.0
    'type'     => 'text',
    'desc_tip' =>  true,
  ),

  array(
    'name'    => __( 'Trailing zeros', 'woocommerce' ),
    'desc'    => __( 'Remove zeros after the decimal point. e.g. $10.00 becomes $10', 'woocommerce' ),
    'id'      => 'woocommerce_price_trim_zeros',
    'std'     => 'yes', // WooCommerce < 2.0
    'default' => 'yes', // WooCommerce >= 2.0
    'type'    => 'checkbox'
  ),

  array( 'type' => 'sectionend', 'id' => 'pricing_options' ),
);

Which will render roughly like:

WooCommerce Settings Pricing Options

By inspecting the settings data structure we see that it consists of an array of arrays, where each child array represents an element (heading, field or section end) on the settings page. A section of settings starts with an array with a type ‘title’, containing a ‘name’, ‘desc’ description and unique ‘id’. Any subsequent arrays are part of that section until we hit a special array with type ‘sectionend’ and an ‘id’ matching that of the starting section element.

The individual settings fields are given as arrays with a number of common arguments, along with some optional ones depending on the field ‘type’:

type
(string) Required field type with some common options: ‘text’, ‘color’, ‘image_width’, ‘select’, ‘checkbox’, ‘textarea’. Also some special case options: ‘single_select_page’, ‘single_select_country’, ‘multi_select_countries’. And you can even define your own custom type, providing the implementation via the woocommerce_admin_field_{mytype} action.
Note: WooCommerce 2.0 introduces some new types: ’email’, ‘pasword’, ‘number’, ‘multiselect’ and ‘radio’.
name
(string) The displayed field name
Note: In WooCommerce 2.0 ‘name’ is replaced by a new field ‘title’, however the new ‘title’ field defaults to ‘name’, so for now at least you’re safe using ‘name’ and compatible with both WC 1.6.6 and previous as well as WC 2.0+
title
(string) WooCommerce 2.0 only This replaces the ‘name’ field in WooCommerce 2.0+, but defaults to ‘name’ if that field is provided.
id
(string) Unique field identifier, used to retrieve the field from the database options table
class
(string) Optional field class names
css
(string) Optional field custom css
std
(mixed) Optional field default value if the field type is ‘text’, ‘color’, ‘image_width’, ‘select’ or ‘textarea’. This can be a string, numeric or array depending on the option field ‘type’
Removed in upcoming WooCommerce 2.0
default
(mixed) Field default value. This can be a string, numeric or array depending on the option field ‘type’
This more appropriately named argument is available only for WooCommerce 2.0 and is available for all field types. For now just use both ‘std’ and ‘default’ with the same value
desc
(string) Optional field description, displayed next to the input element, or used as the tooltip, depending on ‘desc_tip’
desc_tip
(boolean|string) If true and ‘desc’ is provided, ‘desc’ will be used as the field tool tip. If a string is used it will be set as the tool tip.
Note: With WooCommerce 2.0+ you can have both a description and tooltip by using strings for each.
options
(array) Associative array of option name to value, this is used for the ‘select’, ‘multiselect’ or ‘radio’ field types
checkboxgroup
(string) Optional for fields of type ‘checkbox’, value can be one of ‘start’, ” or ‘end’. This is used to create a grouping of checkboxes under a single title/name, and for purposes of showing/hiding some checkboxes based on whether another is checked or not. This allows you to create options that are only visible if another option is checked or not checked.
show_if_checked
(string) Show a checkbox if another is checked. Optional for fields of type ‘checkbox’ that are part of a ‘checkboxgroup’, value can be one of ‘option’, ‘yes’ or ‘no’ (default). Only one checkbox in a checkboxgroup should be marked as ‘option’: this is the checkbox that controls the visibility of the others which have a value of ‘yes’.
hide_if_checked
(string) Hide a checkbox if another is checked. Optional for fields of type ‘checkbox’ that are part of a ‘checkboxgroup’, value can be one of ‘option’, ‘yes’ or ‘no’ (default). Only one checkbox in a checkboxgroup should be marked as ‘option’: this is the checkbox that controls the visibility of the others which have a value of ‘yes’.

I know there are a lot of possible arguments, with all different values which can be confusing and compounded by the changes with upcoming WooCommerce 2.0, but if you ever have any doubts about how something works, or what options you have, take a look at the woocommerce_admin_fields() function found in woocommerce/admin/woocommerce-admin-settings.php. Also the full set of WooCommerce settings can be found in the woocommerce/admin/settings/settings-init.php file and is a great starting point to find an example close to what you want to do.

Remember that if the above standard fields don’t do quite what you’re looking for you can always define your own totally custom option type along with whatever custom arguments you want, by hooking into the woocommerce_admin_field_{mytype} action.

Any setting field value can be retrieved from the database by using the standard WordPress get_option() function with the option’s ‘id’. Ie:

$woocommerce_price_trim_zeros = get_option( 'woocommerce_price_trim_zeros' );

Example

Now with all the formalities and background taken care of, how do we actually add a custom setting option you ask? It’s a simple matter of hooking onto the particular settings filter depending on what tab you want, and adding the option in at the appropriate place in the settings array. Here’s some code from my Sequential Order Numbers Pro plugin which adds a text option named “Order Number Start” to the “General” tab before the end of the “General Options” section:

function add_order_number_start_setting( $settings ) {

  $updated_settings = array();

  foreach ( $settings as $section ) {

    // at the bottom of the General Options section
    if ( isset( $section['id'] ) && 'general_options' == $section['id'] &&
       isset( $section['type'] ) && 'sectionend' == $section['type'] ) {

      $updated_settings[] = array(
        'name'     => __( 'Order Number Start', 'wc_seq_order_numbers' ),
        'desc_tip' => __( 'The starting number for the incrementing portion of the order numbers, unless there is an existing order with a higher number.', 'wc_seq_order_numbers' ),
        'id'       => 'woocommerce_order_number_start',
        'type'     => 'text',
        'css'      => 'min-width:300px;',
        'std'      => '1',  // WC < 2.0
        'default'  => '1',  // WC >= 2.0
        'desc'     => __( 'Sample order number: AA-20130219-000-ZZ', 'wc_seq_order_numbers' ),
      );
    }

    $updated_settings[] = $section;
  }

  return $updated_settings;
}
add_filter( 'woocommerce_general_settings', 'add_order_number_start_setting' );

Which will look like:

WooCommerce Settings Custom Option

Your custom option setting will be automatically saved to the database to the standard WordPress options table with the field ‘id’ as the option name. Retrieve it using the standard WordPress get_option() function. Just don’t forget that if you use a default value for your setting that you’ll have to either set that value with an “install” function, or use it as the second parameter when retrieving your option from the database. For instance:

$order_number_start = get_option( 'woocommerce_order_number_start', 1 );

Published by Justin Stern

Justin is one of our co-founders, and is our resident overengineer. He likes to write developer tutorials and make black magic happen in our plugins. He thinks that writing code is a lot easier than writing words.

30 Comments

  1. Thanks Justin, you rock!

  2. Justin you are the best when it comes to learning new WooCommerce customizations!!! I am gonna get a little crazy here but what if I wanted to add a visual date picker like a little calendar script. All that I needed saved into the option field is the month and day like php getdate() returns. Example Jan 1st – 11 or august 20th 820. But for the user I want them to see the little calendar like produced by one of these scripts: http://www.hongkiat.com/blog/useful-calendar-date-picker-scripts-for-web-developers/.

    • Hey Leon, yeah that would definitely be a nice input type to have. Totally doable of course, but would take a little work by someone

  3. thanks for great tips !

    a question: how to show prices only when the User login?

    not allow add to cart to see the prices too

  4. I would like to know how to remove shipping form digital downloads. I’m creating some brushes and preset for Lightroom 4. Once I create the product and view it at the bottom it wants to calculate the shipping. Is there any way I can remove that function from the downloadable goods?

    -Scot

    • Marking a product as “Virtual” in the product admin should hide any and all shipping fields on checkout. I’d recommend giving that a try.

  5. Hi justin,

    Thanks for the tips, but, it seems that this tip does not work with WC 2.0 😀

    Another question, do you know how to check if a customer (registered user) bought a product many times (2 or more)?

    Thanks in advance.

    -Thy

  6. Where to insert this term “$order_number_start = get_option( ‘woocommerce_order_number_start’, 1 );” ?

    This term “add_filter( ‘woocommerce_gen……” I insert to sequential…, but prefix does not work. 🙁

  7. Hi Justin,

    Thanks for the tutorial. I’ve a little bit of confuse how to set only 9 recent products will diaplay in home page?

    Thanks

  8. Hey there!
    I am not really clear about how to modify your example to include more than one option and in a new section (instead of adding the option at the bottom of an existing one).
    Thanks in advance!

  9. This is just great. Thank you very much!

    Now I’m looking for the code to make the same with tax – whether to include it or no on the frontend.

  10. Justin,

    How does woo handle additional fields other than simple text fields?

    For example, if I wanted to add a select box, normally that’s done with another array using the field type select, but does woo have specific parameters that need to be used?

  11. Hai, could you explain more step to modify the currency position. Which part is need to be editted for adding this code:

    array(
    ‘name’ => __( ‘Currency Position’, ‘woocommerce’ ),
    ‘desc’ => __( ‘This controls the position of the currency symbol.’, ‘woocommerce’ ),
    ‘id’ => ‘woocommerce_currency_pos’,
    ‘css’ => ‘min-width:150px;’,
    ‘std’ => ‘left’, // WooCommerce ‘left’, // WooCommerce >= 2.0
    ‘type’ => ‘select’,
    ‘options’ => array(
    ‘left’ => __( ‘Left’, ‘woocommerce’ ),
    ‘right’ => __( ‘Right’, ‘woocommerce’ ),
    ‘left_space’ => __( ‘Left (with space)’, ‘woocommerce’ ),
    ‘right_space’ => __( ‘Right (with space)’, ‘woocommerce’ )
    ),
    ‘desc_tip’ => true,
    ),

    whats the name of the file I have to edit, and in which section. Thanks in advance.

  12. You guys rock 🙂 that helped a lot and opens up “endless opportunities” with an “if option_id = 1 do this else that” approach. thank you

  13. Hi, how do you add options to one of the sub sections? I am trying to add a field to Emails -> New Order. The field I am specifying is a custom footer used on the E-mail template for “New Orders” only. (I want to add a unique footer setting to all the e-mail templates)

    I would really appreciate some suggestions.

  14. Great article very helpful to get me in the right direction. How would I go about populating an array for a ‘multiselect’ setting with the `’slug’ => ‘name’` of all the product categories set up in a store?

  15. Add this code to a “select” or “multiselect” type and you will get the selections made from the dropdown to populate in the form fields just like the core does:

    `’class’ => ‘chosen_select’,`

  16. i added a function that will add extra fee “Service Fee” of 5% on the cart total and it worked, now my problem is how can i add a form on General Settings so that client can adjust the percentage easily?

    • Hey Ken, the example option from Sequential Order Numbers above is exactly what you need. You can add a text field for this setting, and then in the code that creates the services fee, you’ll have to use get_option( 'id_name' ) to insert this option instead of a hard coded number.

  17. Hello folks!

    I’m trying to insert custom options in the Local Delivery tab, but looks like there is no filter for that. Can you guys help me in achieving that?

    Here is a link about how it is and how I want it to be (“photoshoped”):
    http://goo.gl/wz2TCD

    Thanks in advance.
    Ricardo.

    • Hey Ricardo, I’m afraid there’s no easy way to add settings to that method. You could probably extend the class, but not sure how difficult it’d be to unhook the old and rehook the new one though, as I’ve not done it.

  18. Hey Ricardo, is it possible to add a custom field and multiply the regular price with the custom field value in woocommerce i have used your code & thanks for the code:-

    ‘add_filter( ‘woocommerce_general_settings’, ‘add_order_number_start_setting’ );

    function add_order_number_start_setting( $settings ) {

    $updated_settings = array();
    foreach ( $settings as $section ) {

    //At the bottom of the General Options section

    if ( isset( $section[‘id’] ) && ‘general_options’ == $section[‘id’] &&

    isset( $section[‘type’] ) && ‘sectionend’ == $section[‘type’] ) {

    $updated_settings[] = array(

    'name' => __( 'Convert the Euro', 'wc_seq_order_numbers' ),

    'desc_tip' => __( 'The starting number for the incrementing portion of the order numbers, unless there is an existing order with a higher number.', 'wc_seq_order_numbers' ),

    'id' => 'woocommerce_order_number_start',

    'type' => 'text',

    'css' => 'min-width:300px;',

    'std' => '1', // WC < 2.0

    'default' => '1.6',
    // WC >= 2.0

    /* ‘desc’ => __( ‘Sample order number: AA-20130219-000-ZZ’, ‘wc_seq_order_numbers’ ),
    */
    );

    }
    $updated_settings[] = $section;

    }

    return $updated_settings;
    }

    which adds a custom field in woocommerce setting but i am still looking for an answer for how to multiply the regular price with the custom field value and that will be the price of the product. Is it possible ..????

Hmm, looks like this article is quite old! Its content may be outdated, so comments are now closed.