Looking for a way to present extra details on WooCommerce product pages beyond the standard tabs? This guide shows you how to add custom tabs without losing your work when you update your theme. I’ll show you how to place this code in WPCode—so you can safely manage snippets—and walk you through each step, from registering a Custom Post Type (CPT) to displaying tabs on product pages.
Why Add Custom Tabs to WooCommerce?
Sometimes, product details just don’t fit neatly under “Description” or “Reviews.” You might have special shipping info, sizing charts, or extended warranties. Custom tabs give you that extra room to inform and engage customers in a more structured way. See the screenshot:

How to Add Custom Product Tabs to Woocommerce Single Product Pages?
Option 1: Installation Using WPCode plugin (Recommended Method)
WPCode offers the safest and most user-friendly way to add this feature. Here’s how:
Install WPCode:
- Go to Plugins → Add New
- Search for “WPCode”
- Install and activate the free plugin
Why WPCode instead of the theme’s functions.php? WPCode (or any code snippets plugin) keeps your custom tweaks separate from your theme. So if your theme updates, you won’t lose any changes.
Add the Code Snippet:
- Navigate to Code Snippets → Add Snippet
- Click “Add New Snippet”
- Choose “PHP Snippets” as the code type
- Name your snippet (e.g., “Gutenberg Add New Button”)
- Please copy and paste our provided code
- Set “Location” to “Run Everywhere”
Once you save and activate the snippet, you’re set to move on.
Option 2: Using the functions.php of Your Child Theme
⚠️ Warning: This method requires more technical knowledge and can break your site if not done carefully!
If you’re comfortable editing theme files, you can add the code directly to your child theme’s functions.php file.
Steps:
1. Access Your Child Theme’s functions.php:
- Use FTP or the WordPress Theme Editor (Appearance > Theme Editor).
2. Add the Custom Code:. Paste the same code provided above at the end of the functions.php file.
3. Save the Changes.
Note: Editing the functions.php file can break your site if not done correctly. Always back up your site before making changes.
Next, I’ll show you the different parts of the code and explain what they do. If you want to see the full code, scroll down to the bottom and view it there.
Register the Custom Post Type (CPT)
The snippet below creates a CPT named Custom Tabs and places it in your WooCommerce menu. This allows you to add global tabs that apply to multiple products.
// Register 'Custom Tabs' Custom Post Type
function register_custom_tabs_cpt() {
$args = array(
'labels' => array(
'name' => __('Custom Tabs', 'your-textdomain'),
'singular_name' => __('Custom Tab', 'your-textdomain'),
'menu_name' => __('Custom Tabs', 'your-textdomain'),
'add_new' => __('Add New', 'your-textdomain'),
'add_new_item' => __('Add New Custom Tab', 'your-textdomain'),
'edit_item' => __('Edit Custom Tab', 'your-textdomain'),
'new_item' => __('New Custom Tab', 'your-textdomain'),
),
'public' => false,
'show_ui' => true,
'show_in_menu' => 'edit.php?post_type=product',
'capability_type' => 'post',
'hierarchical' => false,
'supports' => array('title', 'editor'),
'menu_icon' => 'dashicons-welcome-widgets-menus',
'show_in_rest' => true, // Enables Gutenberg support
);
register_post_type('custom_product_tab', $args);
}
add_action('init', 'register_custom_tabs_cpt');
How It Integrates
• show_in_menu attaches our CPT to the WooCommerce products menu.
• show_in_rest enables the Gutenberg editor for these custom tabs.
4. Add Meta Boxes for Product Categories
Want certain tabs to appear only for specific product categories? Here’s how:
// Add Product Category Meta Box to Custom Tabs
function add_custom_tab_meta_box() {
add_meta_box(
'custom_tab_product_categories',
__('Assign to Product Categories', 'your-textdomain'),
'render_custom_tab_meta_box',
'custom_product_tab',
'side',
'default'
);
}
add_action('add_meta_boxes', 'add_custom_tab_meta_box');
// Render the Meta Box
function render_custom_tab_meta_box($post) {
$selected_categories = get_post_meta($post->ID, '_custom_tab_product_categories', true);
$selected_categories = is_array($selected_categories) ? $selected_categories : array();
$product_categories = get_terms(array(
'taxonomy' => 'product_cat',
'hide_empty' => false,
));
echo '<p>Select product categories for this tab:</p>';
echo '<ul>';
foreach ($product_categories as $category) {
$checked = in_array($category->term_id, $selected_categories) ? 'checked' : '';
echo '<li><label><input type="checkbox" name="custom_tab_product_categories[]" value="' . esc_attr($category->term_id) . '" ' . $checked . '> ' . esc_html($category->name) . '</label></li>';
}
echo '</ul>';
}
// Save Selected Product Categories
function save_custom_tab_meta($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (isset($_POST['custom_tab_product_categories'])) {
$selected_categories = array_map('sanitize_text_field', $_POST['custom_tab_product_categories']);
update_post_meta($post_id, '_custom_tab_product_categories', $selected_categories);
} else {
delete_post_meta($post_id, '_custom_tab_product_categories');
}
}
add_action('save_post', 'save_custom_tab_meta');
Practical Example
Imagine you have “Hoodies” and “T-Shirts” as product categories. You can create a “Fabric Care” custom tab and assign it only to “Hoodies.” This ensures the tab only shows where needed.
Display the Tabs on Product Pages
This code fetches global custom tabs (from the CPT) that match the product’s categories and merges them with any product-specific tabs.
// Display Global and Product-Specific Tabs on Product Pages
function display_global_custom_tabs($tabs) {
global $post;
if (!$post) return $tabs;
// Get the product categories
$product_categories = wp_get_post_terms($post->ID, 'product_cat', array('fields' => 'ids'));
// Fetch all published global tabs
$global_tabs = get_posts(array(
'post_type' => 'custom_product_tab',
'posts_per_page' => -1,
'post_status' => 'publish',
));
// Merge global tabs if they match product categories
foreach ($global_tabs as $tab) {
$assigned_categories = get_post_meta($tab->ID, '_custom_tab_product_categories', true);
if (is_array($assigned_categories) && array_intersect($assigned_categories, $product_categories)) {
$tabs['global_tab_' . $tab->ID] = array(
'title' => get_the_title($tab->ID),
'priority' => 40,
'callback' => 'render_global_custom_tab_content',
'content' => apply_filters('the_content', get_post_field('post_content', $tab->ID)),
);
}
}
// Add a single product's custom tab
$custom_tab_title = get_post_meta($post->ID, '_custom_tab_title', true);
$custom_tab_content = get_post_meta($post->ID, '_custom_tab_content', true);
if (!empty($custom_tab_title) && !empty($custom_tab_content)) {
$tabs['custom_tab'] = array(
'title' => esc_html($custom_tab_title),
'priority' => 50,
'callback' => 'render_custom_tab_content',
'content' => apply_filters('the_content', $custom_tab_content),
);
}
return $tabs;
}
add_filter('woocommerce_product_tabs', 'display_global_custom_tabs');
// Render Global Custom Tab Content
function render_global_custom_tab_content($key, $tab) {
echo '<div class="woocommerce-global-tab-content">';
echo do_shortcode(wpautop($tab['content']));
echo '</div>';
}
// Render Single Product Custom Tab Content
function render_custom_tab_content($key, $tab) {
echo '<div class="woocommerce-custom-tab-content">';
echo do_shortcode(wpautop($tab['content']));
echo '</div>';
}
Product-Specific Tabs
You can store extra details on a per-product basis. Your customer sees a special tab only on that product’s page.
Adding a Custom Tab in the Product Edit Screen
These functions create a “Custom Tab” panel in your product’s edit screen, letting you fill in a title and content that appear as a separate tab.
// Register Custom Tab in Product Edit Page
function add_custom_product_tab($tabs) {
$tabs['custom_tab'] = array(
'label' => __('Custom Tab', 'your-textdomain'),
'target' => 'custom_product_data',
'class' => array('show_if_simple', 'show_if_variable'),
'priority' => 50,
);
return $tabs;
}
add_filter('woocommerce_product_data_tabs', 'add_custom_product_tab');
// Add Custom Tab Fields
function custom_product_tab_content() {
global $post;
$custom_tab_title = get_post_meta($post->ID, '_custom_tab_title', true);
$custom_tab_content = get_post_meta($post->ID, '_custom_tab_content', true);
?>
<div id="custom_product_data" class="panel woocommerce_options_panel">
<div class="options_group">
<?php
woocommerce_wp_text_input(array(
'id' => '_custom_tab_title',
'label' => __('Custom Tab Title', 'your-textdomain'),
'value' => esc_attr($custom_tab_title),
));
?>
<p class="form-field">
<label for="_custom_tab_content"><?php _e('Custom Tab Content', 'your-textdomain'); ?></label>
<?php
wp_editor(
$custom_tab_content,
'_custom_tab_content',
array(
'textarea_name' => '_custom_tab_content',
'media_buttons' => true,
'textarea_rows' => 8,
)
);
?>
</p>
</div>
</div>
<?php
}
add_action('woocommerce_product_data_panels', 'custom_product_tab_content');
// Save Custom Tab Data
function save_custom_product_tab_data($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (isset($_POST['_custom_tab_title'])) {
update_post_meta($post_id, '_custom_tab_title', sanitize_text_field($_POST['_custom_tab_title']));
}
if (isset($_POST['_custom_tab_content'])) {
update_post_meta($post_id, '_custom_tab_content', wp_kses_post($_POST['_custom_tab_content']));
}
}
add_action('woocommerce_process_product_meta', 'save_custom_product_tab_data');
Complete Code for Adding Custom Product Tabs to WooCommerce Single Product Pages
Here’s the complete code with all the parts mentioned above included.
// Add Custom Product Tabs to Woocommerce Single Product Pages
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
/**
* Register 'Custom Tabs' Custom Post Type with Gutenberg Support
*/
function register_custom_tabs_cpt() {
$args = array(
'labels' => array(
'name' => __('Custom Tabs', 'your-textdomain'),
'singular_name' => __('Custom Tab', 'your-textdomain'),
'menu_name' => __('Custom Tabs', 'your-textdomain'),
'add_new' => __('Add New', 'your-textdomain'),
'add_new_item' => __('Add New Custom Tab', 'your-textdomain'),
'edit_item' => __('Edit Custom Tab', 'your-textdomain'),
'new_item' => __('New Custom Tab', 'your-textdomain'),
),
'public' => false,
'show_ui' => true,
'show_in_menu' => 'edit.php?post_type=product',
'capability_type' => 'post',
'hierarchical' => false,
'supports' => array('title', 'editor'),
'menu_icon' => 'dashicons-welcome-widgets-menus',
'show_in_rest' => true, // ✅ Enables Gutenberg support
);
register_post_type('custom_product_tab', $args);
}
add_action('init', 'register_custom_tabs_cpt');
/**
* Add Product Category Meta Box to Custom Tabs
*/
function add_custom_tab_meta_box() {
add_meta_box(
'custom_tab_product_categories',
__('Assign to Product Categories', 'your-textdomain'),
'render_custom_tab_meta_box',
'custom_product_tab',
'side',
'default'
);
}
add_action('add_meta_boxes', 'add_custom_tab_meta_box');
/**
* Render Product Category Meta Box
*/
function render_custom_tab_meta_box($post) {
$selected_categories = get_post_meta($post->ID, '_custom_tab_product_categories', true);
$selected_categories = is_array($selected_categories) ? $selected_categories : array();
$product_categories = get_terms(array(
'taxonomy' => 'product_cat',
'hide_empty' => false,
));
echo '<p>' . __('Select product categories for this tab:', 'your-textdomain') . '</p>';
echo '<ul>';
foreach ($product_categories as $category) {
$checked = in_array($category->term_id, $selected_categories) ? 'checked' : '';
echo '<li><label><input type="checkbox" name="custom_tab_product_categories[]" value="' . esc_attr($category->term_id) . '" ' . $checked . '> ' . esc_html($category->name) . '</label></li>';
}
echo '</ul>';
}
/**
* Save Selected Product Categories for Custom Tabs
*/
function save_custom_tab_meta($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (isset($_POST['custom_tab_product_categories'])) {
$selected_categories = array_map('sanitize_text_field', $_POST['custom_tab_product_categories']);
update_post_meta($post_id, '_custom_tab_product_categories', $selected_categories);
} else {
delete_post_meta($post_id, '_custom_tab_product_categories');
}
}
add_action('save_post', 'save_custom_tab_meta');
/**
* Display Global Custom Tabs on Product Pages with Proper Styling
*/
function display_global_custom_tabs($tabs) {
global $post;
if (!$post) return $tabs;
$product_categories = wp_get_post_terms($post->ID, 'product_cat', array('fields' => 'ids'));
$args = array(
'post_type' => 'custom_product_tab',
'posts_per_page' => -1,
'post_status' => 'publish',
);
$global_tabs = get_posts($args);
foreach ($global_tabs as $tab) {
$assigned_categories = get_post_meta($tab->ID, '_custom_tab_product_categories', true);
if (is_array($assigned_categories) && array_intersect($assigned_categories, $product_categories)) {
$tabs['global_tab_' . $tab->ID] = array(
'title' => esc_html(get_the_title($tab->ID)),
'priority' => 40,
'callback' => 'render_global_custom_tab_content',
'content' => apply_filters('the_content', get_post_field('post_content', $tab->ID)),
);
}
}
// Add custom tab to the product tabs array
$custom_tab_title = get_post_meta($post->ID, '_custom_tab_title', true);
$custom_tab_content = get_post_meta($post->ID, '_custom_tab_content', true);
if (!empty($custom_tab_title) && !empty($custom_tab_content)) {
$tabs['custom_tab'] = array(
'title' => esc_html($custom_tab_title),
'priority' => 50,
'callback' => 'render_custom_tab_content',
'content' => apply_filters('the_content', $custom_tab_content),
);
}
return $tabs;
}
add_filter('woocommerce_product_tabs', 'display_global_custom_tabs');
/**
* Render Global Custom Tab Content with Proper Styles
*/
function render_global_custom_tab_content($key, $tab) {
echo '<div class="woocommerce-global-tab-content">';
echo do_shortcode(wpautop($tab['content']));
echo '</div>';
}
/**
* Render Custom Tab Content
*/
function render_custom_tab_content($key, $tab) {
echo '<div class="woocommerce-custom-tab-content">';
echo do_shortcode(wpautop($tab['content']));
echo '</div>';
}
/**
* Enqueue Gutenberg Frontend Styles for Global Tabs
*/
function enqueue_gutenberg_styles_for_tabs() {
if (is_product()) {
wp_enqueue_style('wp-block-library'); // Core Gutenberg styles
}
}
add_action('wp_enqueue_scripts', 'enqueue_gutenberg_styles_for_tabs');
/**
* Register Custom Tab in Product Edit Page
*/
function add_custom_product_tab($tabs) {
$tabs['custom_tab'] = array(
'label' => __('Custom Tab', 'your-textdomain'),
'target' => 'custom_product_data',
'class' => array('show_if_simple', 'show_if_variable'),
'priority' => 50,
);
return $tabs;
}
add_filter('woocommerce_product_data_tabs', 'add_custom_product_tab');
/**
* Add Custom Tab Fields to Product Edit Page
*/
function custom_product_tab_content() {
global $post;
$custom_tab_title = get_post_meta($post->ID, '_custom_tab_title', true);
$custom_tab_content = get_post_meta($post->ID, '_custom_tab_content', true);
?>
<div id="custom_product_data" class="panel woocommerce_options_panel">
<div class="options_group">
<?php
woocommerce_wp_text_input(array(
'id' => '_custom_tab_title',
'label' => __('Custom Tab Title', 'your-textdomain'),
'value' => esc_attr($custom_tab_title),
));
?>
<p class="form-field">
<label for="_custom_tab_content"><?php _e('Custom Tab Content', 'your-textdomain'); ?></label>
<?php
wp_editor(
$custom_tab_content,
'_custom_tab_content',
array(
'textarea_name' => '_custom_tab_content',
'media_buttons' => true,
'textarea_rows' => 8,
)
);
?>
</p>
</div>
</div>
<?php
}
add_action('woocommerce_product_data_panels', 'custom_product_tab_content');
/**
* Save Custom Tab Data
*/
function save_custom_product_tab_data($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (isset($_POST['_custom_tab_title'])) {
update_post_meta($post_id, '_custom_tab_title', sanitize_text_field($_POST['_custom_tab_title']));
}
if (isset($_POST['_custom_tab_content'])) {
update_post_meta($post_id, '_custom_tab_content', wp_kses_post($_POST['_custom_tab_content']));
}
}
add_action('woocommerce_process_product_meta', 'save_custom_product_tab_data');
Troubleshooting Common Issues
1. Tabs Not Appearing
- Make sure you have published your custom tabs (not left them as drafts).
- Double-check that you’re assigning the correct categories.
2. Meta Box Values Not Saving
- Confirm that DOING_AUTOSAVE isn’t interfering.
- Check user permissions (you need the correct capability to edit/post).