WooCommerce renders three default tabs on every single product page: Description (the main post content), Additional Information (attributes and dimensions), and Reviews. For most stores, these are not enough — you may need a Shipping & Returns tab, a Video tab, a Downloads tab for digital products, or a custom tab whose content comes from a custom field. WooCommerce exposes the complete tab system through a single filter: woocommerce_product_tabs. Each tab is an array entry with a title, a priority (controls tab order), and a callback (the function that renders the tab content panel). Adding a tab is as simple as appending a new entry to the array. Removing a default tab is done with unset() on the known keys (description, additional_information, reviews). Modifying an existing tab’s title or priority is done by directly overwriting the array entry. This is far cleaner than JavaScript-based tab injection and works correctly with WooCommerce’s built-in tab accessibility markup (ARIA roles and keyboard navigation). Tab content is output inside a <div id="tab-{key}"> panel that WooCommerce styles and makes accessible automatically. Combine custom tabs with the product gallery guide and price display guide for a fully customised product page.
Problem: The default WooCommerce product tabs (Description, Additional Information, Reviews) do not match your store’s needs and you want to add, remove, or rename them without a plugin.
Solution: Add the following code to your theme’s functions.php file:
add_filter( 'woocommerce_product_tabs', 'helloadmin_custom_product_tabs' );
function helloadmin_custom_product_tabs( array $tabs ): array {
// Remove the Reviews tab
unset( $tabs['reviews'] );
// Rename the Description tab
if ( isset( $tabs['description'] ) ) {
$tabs['description']['title'] = __( 'Product Details', 'woocommerce' );
}
// Move Additional Information to appear last (priority 50 → 30)
if ( isset( $tabs['additional_information'] ) ) {
$tabs['additional_information']['priority'] = 30;
}
// Add a Shipping & Returns tab
$tabs['shipping_returns'] = [
'title' => __( 'Shipping & Returns', 'woocommerce' ),
'priority' => 40,
'callback' => 'helloadmin_shipping_returns_tab',
];
// Add a custom tab from a product custom field
global $product;
$video_url = $product ? get_post_meta( $product->get_id(), '_helloadmin_video_url', true ) : '';
if ( $video_url ) {
$tabs['video'] = [
'title' => __( 'Video', 'woocommerce' ),
'priority' => 20,
'callback' => 'helloadmin_video_tab',
];
}
return $tabs;
}
// Tab content callbacks
function helloadmin_shipping_returns_tab(): void {
// You can also use get_option() to pull from a settings page
echo '<h2>' . esc_html__( 'Shipping & Returns', 'woocommerce' ) . '</h2>';
echo '<p>' . esc_html__( 'We ship worldwide. Orders are dispatched within 2 business days. Returns accepted within 30 days of delivery.', 'woocommerce' ) . '</p>';
}
function helloadmin_video_tab(): void {
global $product;
if ( ! $product ) {
return;
}
$video_url = esc_url( get_post_meta( $product->get_id(), '_helloadmin_video_url', true ) );
if ( ! $video_url ) {
return;
}
echo '<h2>' . esc_html__( 'Product Video', 'woocommerce' ) . '</h2>';
printf(
'<div class="product-video-wrapper">
<iframe width="560" height="315" src="%s" allowfullscreen loading="lazy"></iframe>
</div>',
$video_url
);
}
NOTE: Tab priorities determine display order — lower numbers appear first. The default priorities are: Description = 10, Additional Information = 20, Reviews = 30. Removing the Reviews tab via unset( $tabs[‘reviews’] ) only removes the tab on the front end; WooCommerce still allows customers to submit reviews via the admin. If you want to disable reviews completely, also go to WooCommerce → Settings → Products and uncheck “Enable product reviews”. Custom tab content callbacks should always escape output with esc_html() or wp_kses_post() — never echo raw post meta values directly.