Deprecating plugin functions and hooks (and what we did in WooCommmerce)

Sometimes code needs to change; without doing so you can end up with a non-consistent, bloated mess. When changing things such as functions and hooks however, you do have to consider backwards compatibility so that code which relies on the old things doesn’t just stop breaking without explanation.

In WooCommerce major releases we often have to deal with this problem – in this post I’ll explain how to deprecate code, and how we dealt with it whilst developing 2.1.

How to deprecate code with a warning

There are 3 deprecated functions in WordPress core for telling the user something is being done wrong (when WP_DEBUG is enabled). These are _deprecated_function, _deprecated_argument and _deprecated_file.

You can pass each the name of the function/arg/file and the version in which it was deprecated. With files and functions you can also pass in the replacement (if it exists) and this will also inform the user. Args and files can also be passed some additional explanation via a message (I’ve been pushing for this to be added to deprecated_function for 10 months too, but I’m not making much headway -.-).

[php]_deprecated_function( $function, $version, $replacement );[/php]

[php]_deprecated_argument( $function, $version, $message );[/php]

[php]_deprecated_file( $file, $version, $replacement = null, $message = ” );[/php]

Here is an example in context from WooCommerce:

[php]_deprecated_argument( ‘WC_Checkout::process_checkout()’, ‘2.1’, ‘The “shiptobilling” field is deprecated. The template files are out of date’ );[/php]

If triggered this will output:

NOTICE: WC_Checkout::process_checkout() was called with an argument that is <strong>deprecated</strong> since version 2.1! The “shiptobilling” field is deprecated. The template files are out of date

Deprecating WC functions

To keep things tidy, we moved most deprecated functions to wc-deprecated-functions.php where we declared the old function with a notice and a call to the new function.

Here is an example from that file:

[php]function woocommerce_readfile_chunked( $file, $retbytes = true ) {
_deprecated_function( ‘woocommerce_readfile_chunked’, ‘2.1’, ‘WC_Download_Handler::readfile_chunked()’ );
return WC_Download_Handler::readfile_chunked( $file, $retbytes );

As you can see, this calls the new method, meaning old code won’t break (for now). If the user has WP_DEBUG on, they will be notified.

Since they are also in a single file, when we do remove them (most likely after major 2 point releases) they are easy to locate.

Deprecating WC methods

Methods need to be kept in the same class and cannot be moved. The setup is similar to the functions though. Here is an example from the WooCommerce main class:

[php]public function force_ssl( $content ) {
_deprecated_function( ‘Woocommerce->force_ssl’, ‘2.1’, ‘WC_HTTPS::force_https_url’ );
return WC_HTTPS::force_https_url( $content );

Depreciating WC filter hooks

When filter names change, there isn’t a built in way to handle this. In 2.1, I built a simple filter mapper, to map the old filter’s hooked in functions to the new filter. This prevents hooked in code from breaking.

Here is a sample:

* Handle renamed filters
global $wc_map_deprecated_filters;
$wc_map_deprecated_filters = array(
'woocommerce_cart_item_class' => 'woocommerce_cart_table_item_class'
foreach ( $wc_map_deprecated_filters as $new => $old )
add_filter( $new, 'woocommerce_deprecated_filter_mapping' );
function woocommerce_deprecated_filter_mapping( $data, $arg_1 = '', $arg_2 = '', $arg_3 = '' ) {
global $wc_map_deprecated_filters;
$filter = current_filter();
if ( isset( $wc_map_deprecated_filters[ $filter ] ) )
if ( has_filter( $wc_map_deprecated_filters[ $filter ] ) ) {
$data = apply_filters( $wc_map_deprecated_filters[ $filter ], $data, $arg_1, $arg_2, $arg_3 );
_deprecated_function( 'The ' . $wc_map_deprecated_filters[ $filter ] . ' filter', '2.1', $filter );
return $data;

view raw
hosted with ❤ by GitHub

In the above example, we’re mapping woocommerce_cart_table_item_class to the new filter called woocommerce_cart_item_class. To map more, they are just defined as key/value pairs in the $wc_map_deprecated_filters array. This appears to work well.

Soft deprecation

Some functions were just renamed for consistency in 2.1, losing the woocommerce_ prefix for a shorter wc_. To avoid making too much work for devs we decided to “soft deprecate” them. That is, define them as an alias for now, so going forward the new function names are used, and then in a few versions deprecate them. It would be better (for us) to remove them all now, but to ease the transition we thought it best to keep the old ones there without notices.

All in the name of progress

Changes to functions can be frustrating for developers, but in order to progress they are a necessary evil. Using deprecated functions at least keep code functioning giving developers a chance to update their code, and shouldn’t affect live sites anyway (because live stores should never have debugging visible!).