This is how you can (or should) remove the default Shortcode:
// Hook after `WC_Shortcodes::init()` is executed.
add_action( 'init', function(){
// Remove the shortcode.
remove_shortcode( 'product_categories' );
// Add it back, but using our callback.
add_shortcode( 'product_categories', 'my_product_categories_shortcode' );
}, 11 );
And here’s how you can modify the default Shortcode’s output:
function my_product_categories_shortcode( $atts ) {
$out = WC_Shortcodes::product_categories( $atts );
// Modify the wrapper's opening tag.
if ( ! empty( $atts['class'] ) ) {
$columns = isset( $atts['columns'] ) ?
absint( $atts['columns'] ) : 4;
$out = str_replace(
'<div class="woocommerce columns-' . $columns . '">',
'<div class="woocommerce columns-' . $columns . ' ' . esc_attr( $atts['class'] ) . '">',
$out
);
}
return $out;
}
Or if you want, you can copy the whole code (i.e. clone it) and then do whatever your heart desires:
function my_product_categories_shortcode( $atts ) {
if ( isset( $atts['number'] ) ) {
$atts['limit'] = $atts['number'];
}
$atts = shortcode_atts( array(
'limit' => '-1',
'orderby' => 'name',
'order' => 'ASC',
'columns' => '4',
'hide_empty' => 1,
'parent' => '',
'ids' => '',
'class' => '', // the extra arg
), $atts, 'product_categories' );
// ... refer to the link I provided
return '<div class="woocommerce columns-' . $columns . ' ' . esc_attr( $atts['class'] ) . '">' .
ob_get_clean() . '</div>';
}