Settings Page Infrastructure Refactor

tl;dr

WooCommerce 5.5 will include an extensive refactoring of the settings pages infrastructure. While there are no breaking changes, there’s a new preferred way of structuring settings pages classes, and existing extensions that add their own settings should be tested extensively with the refactored infrastructure in place.

The details

The problem

The settings pages in WooCommerce are organized as classes that inherit from the abstract WC_Settings_Page base class, one class per settings tab. This class has a public get_settings() method that returns structured information for the settings to display on the page.

Settings pages can have multiple sections. In this case, the class also implements a get_sections method that returns an associative array of section ids to section names, and the method to get the settings had its signature changed to get_settings( $current_section = '' ).

This approach had a number of issues:

  • There was no way to add new sections to the existing WooCommerce settings pages that didn’t have defined sections already (since those had the simple get_settings() method version).
  • Each derived class implementing get_settings() from scratch meant that there was a significant amount of duplicate code, especially for triggering actions.
  • The get_settings methods were often implemented as a long chain of if ('foo' === $current_section) { return /* a ton of settings */ } else if ('bar' === $current_section) { return /* a different ton of settings */ } else...

Arguably, the last two are more a consequence of suboptimal code than the settings infrastructure itself; but it was something that would benefit from a refactor anyway.

The solution

The refactor consists of the following changes in the WC_Settings_Page class:

  • A new public get_settings_for_section( $section_id ) method is introduced.
    • This method is final. It’s not intended to be overridden by derived classes.
    • The method searches for a method named get_settings_for_{$section_id}_section in the class, and executes it if found (for the default section, whose id is '', the method searched is get_settings_for_default_section).
  • A new protected get_settings_for_section_core( $section_id ) method is introduced, it will be executed by get_settings_for_section if no suitable get_settings_for_{$section_id}_section method is found. By default this method returns an empty array.
  • The existing get_settings method is now deprecated, but WooCommerce will still use it instead of get_settings_for_section for compatibility with existing settings pages.

All the built-in settings pages in WooCommerce have been refactored according to this new structure, and so it’s now possible to add new sections to any of these pages.

You may be wondering why we are adding a new get_settings_for_section method instead of modifying the original method signature to get_settings( $current_section = '' ) in the base class. That was actually the first approach followed for the refactor, but this breaks in PHP 8 when derived classes override the method as get_settings(); thus, a new method was the only effective solution.

How can I tell if this affects me?

You may be affected if you are the owner/maintainer of an extension or theme that adds custom settings (either via hooks or via implementing settings classes).

If you plan to add new settings pages to your extensions by creating new settings classes that inherit from WC_Settings_Page, please be aware of the new preferred way to implement these (either adding get_settings_for_{$section_id}_section methods, or overriding get_settings_for_section_core. Or both!)

If you have existing settings classes that override get_settings, code-wise no action should be needed as these classes will continue to work. You may want to refactor them to use the new approach, but that’s entirely optional.

What action should I take?

Once the first beta of WooCommerce 5.5 is released please test it with your extension. After it is available, our handy WooCommerce Beta Tester plugin allows you to switch between beta versions and release candidates. If you encounter any issue related to the settings pages please post a bug report in GitHub so that we can take a look.


One response to “Settings Page Infrastructure Refactor”

  1. Is there an example anywhere that includes backcompatibility for older versions where get_settings_for_default_section() does not exist?

Leave a Reply

Your email address will not be published. Required fields are marked *