Skip to content
ThemesIonic — home
WooCommerce

Customising the WooCommerce Product Tabs

Three tabs ship by default and one of them appears only under conditions most stores never meet. Removing the reviews tab hides the tab without switching reviews off, which is rarely what anyone intended.

4 min read intermediate

Two of the three default tabs are conditional, which is why removing one so often appears to do nothing. woocommerce_product_tabs hands you an array describing the tab strip on the single product page. What is in that array depends on the product being viewed, so a snippet tested against one product can behave differently on the next.

The array and what puts things in it

Key Appears when Default priority
description The product has a long description 10
additional_information The product has weight, dimensions or visible attributes 20
reviews Reviews are enabled for products 30

Each entry holds a title, a priority and a callback. Adding one means supplying all three:

add_filter( 'woocommerce_product_tabs', 'ti_product_tabs' );

function ti_product_tabs( $tabs ) {
	$tabs['ti_delivery'] = array(
		'title'    => __( 'Delivery', 'your-textdomain' ),
		'priority' => 25,
		'callback' => 'ti_delivery_tab_content',
	);

	return $tabs;
}

function ti_delivery_tab_content() {
	echo '<h2>' . esc_html__( 'Delivery', 'your-textdomain' ) . '</h2>';
	echo '<p>' . esc_html__( 'Dispatched within two working days.', 'your-textdomain' ) . '</p>';
}

The callback echoes. It does not return. WooCommerce invokes it with call_user_func and ignores whatever comes back, so a callback built like a shortcode handler produces a tab whose panel is blank — the most common report on this hook and the least obvious from the code.

Priority decides order, not array position

Placing your entry at the top of the array changes nothing. The strip is sorted by the priority value, which is why the defaults are numbered in tens: the gaps exist so a new tab can slot between them without renumbering. Priority 25 lands between additional information and reviews. Two tabs sharing a priority fall back to array order, which is stable but not something to rely on.

Removing tabs, and what removal does not do

add_filter( 'woocommerce_product_tabs', 'ti_drop_tabs', 98 );

function ti_drop_tabs( $tabs ) {
	unset( $tabs['reviews'] );

	return $tabs;
}

A late priority such as 98 matters here. Plugins add their tabs on this same filter, and unsetting at the default 10 runs before they have added anything — the tab you meant to remove is put back a moment later by code that ran after you.

What removal does not do is switch the underlying feature off:

  • Removing reviews hides the panel. Ratings continue to render on the product and in the product grid, structured data still advertises them, and the review form is still reachable. Disabling reviews properly means turning off comments for the product post type as well.
  • Removing additional_information hides the table of weight, dimensions and attributes. The attribute data itself is untouched and still drives variations, as covered in product variations.
  • Removing description hides the long description from the tab strip only. It remains in the post content and in search.

Renaming instead of removing

Most requests that arrive as "remove the tab" are really "the label is wrong". Renaming avoids every side effect above:

$tabs['description']['title'] = __( 'About this product', 'your-textdomain' );

Check the key exists before writing to it. On a product with no long description, $tabs['description'] is absent, and assigning into it creates a malformed entry with a title and no callback — a tab that renders as a clickable heading over an empty panel.

When the tabs are not there at all

A single product template built from blocks renders its own layout and may not call the tabs template at all, in which case the filter runs and the result is never used. The same applies to a theme that ships its own single-product.php and prints the description directly. Confirm which template is in play before debugging the array, and switch to a default theme for one page load as the fastest test.

If the tab strip renders but a specific panel stays empty or the wrong panel opens, the cause is usually the callback rather than the array, and the symptoms are catalogued under product data tabs not working.

Verify across three products

Test on a product with dimensions, a product without, and a variable product. The array differs in all three cases, and a snippet that assumes a key exists will either do nothing or produce a broken entry on the products where it does not. Checking one product proves almost nothing here, in the same way that checking one product proves nothing about image sizes.

Frequently asked

Because it was probably not there. That tab renders only when the product has weight, dimensions or visible attributes. On a catalogue of simple products with none of those, WooCommerce never adds it, so there is nothing for your code to remove.
The tab and the review system are separate. Removing the tab hides one panel; ratings still render on the product and in the loop, and reviews are still accepted. Turn off comments for products as well if the intent is to disable reviews.
The callback almost certainly returns its markup instead of echoing it. WooCommerce calls the callback and does not use the return value, so a returned string is discarded and the panel renders empty.

Related guides