1

I used the answer from this question to create my custom product tabs: Custom metabox content displayed in single product additional tabs on Woocommerce

Here's my code:

// Add a custom metabox
add_action( 'add_meta_boxes', 'additional_product_tabs_metabox' );
function additional_product_tabs_metabox()
{
    add_meta_box(
        'add_product_metabox_additional_tabs',
        __( 'Additional product Tabs', 'woocommerce' ),
        'additional_product_tabs_metabox_content',
        'product',
        'normal',
        'high'
    );
}

//  Add custom metabox content
function additional_product_tabs_metabox_content( $post )
{
    // Shipping
    echo '<h4>' . __( 'Shipping', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_shipping', true );
    wp_editor( $value, '_custom_shipping', array( 'editor_height' => 100 ) );

    // Color
    echo '<br><hr><h4>' . __( 'Color', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_color', true );
    wp_editor( $value, '_custom_color', array( 'editor_height' => 100 ) );


    // Material
    echo '<br><hr><h4>' . __( 'Material', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_material', true );
    wp_editor( $value, '_custom_material', array( 'editor_height' => 100 ) );


    // Size
    echo '<br><hr><h4>' . __( 'Size', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_size', true );
    wp_editor( $value, '_custom_size', array( 'editor_height' => 100 ) );


    // Nonce field (for security)
    echo '<input type="hidden" name="additional_product_tabs_nonce" value="' . wp_create_nonce() . '">';
}


// Save product data
add_action( 'save_post_product', 'save_additional_product_tabs', 10, 1 );
function save_additional_product_tabs( $post_id ) {

    // Security check
    if ( ! isset( $_POST[ 'additional_product_tabs_nonce' ] ) ) {
        return $post_id;
    }

    //Verify that the nonce is valid.
    if ( ! wp_verify_nonce( $_POST[ 'additional_product_tabs_nonce' ] ) ) {
        return $post_id;
    }

    // If this is an autosave, our form has not been submitted, so we don't want to do anything.
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return $post_id;
    }

    if ( ! current_user_can( 'edit_product', $post_id ) ) {
        return $post_id;
    }

    // Sanitize user input and save the post meta fields values.

    if( isset($_POST[ '_custom_shipping' ]) )
        update_post_meta( $post_id, '_custom_shipping', wp_kses_post($_POST[ '_custom_shipping' ]) );

    if( isset($_POST[ '_custom_color' ]) )
        update_post_meta( $post_id, '_custom_color', wp_kses_post($_POST[ '_custom_color' ]) );

    if( isset($_POST[ '_custom_material' ]) )
        update_post_meta( $post_id, '_custom_material', wp_kses_post($_POST[ '_custom_material' ]) );

    if( isset($_POST[ '_custom_size' ]) )
        update_post_meta( $post_id, '_custom_size', wp_kses_post($_POST[ '_custom_size' ]) );
}

add_filter( 'woocommerce_product_tabs', 'woo_custom_product_tabs' );
function woo_custom_product_tabs( $tabs ) {

    // 1) Removing tabs

    unset( $tabs['description'] );              // Remove the description tab
    unset( $tabs['additional_information'] );   // Remove the additional information tab

    // 2 Adding new tabs and set the right order

    //Adds Shipping Tab
    $tabs['custom_shipping_tab'] = array(
        'title'     => __( 'Shipping', 'woocommerce' ),
        'priority'  => 10,
        'callback'  => 'woo_custom_shipping_tab_content'
    );

    // Adds Color Tab
    $tabs['custom_color_tab'] = array(
        'title'     => __( 'Color', 'woocommerce' ),
        'priority'  => 20,
        'callback'  => 'woo_custom_color_tab_content'
    );

    // Adds Material Tab
    $tabs['custom_material_tab'] = array(
        'title'     => __( 'Material', 'woocommerce' ),
        'priority'  => 30,
        'callback'  => 'woo_custom_material_tab_content'
    );

    // Adds Size Tab
    $tabs['custom_size_tab'] = array(
        'title'     => __( 'Size', 'woocommerce' ),
        'priority'  => 40,
        'callback'  => 'woo_custom_size_tab_content'
    );

    return $tabs;
}


function woo_custom_shipping_tab_content()  {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_shipping' ) . '</p></div>';
}

function woo_custom_color_tab_content()  {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_color' ) . '</p></div>';
}

function woo_custom_material_tab_content()  {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_material' ) . '</p></div>';
}

function woo_custom_size_tab_content()  {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_size' ) . '</p></div>';
}

Then I added custom code to create vertical tabs and added them after woocommerce_share hook.

/* Vertical Product Tabs */
add_action( 'woocommerce_share', 'woocommerce_output_product_data_tabs', 5 );
function woocommerce_output_product_data_tabs() {
 
    $product_tabs = apply_filters( 'woocommerce_product_tabs', array() );
 
    if ( empty( $product_tabs ) ) {
        return;
    }
 
    foreach ( $product_tabs as $key => $product_tab ) {
 
        echo '<div id="tab-' . esc_attr( $key ) . '">';
 
        if ( isset( $product_tab[ 'callback' ] ) ) {
            call_user_func( $product_tab[ 'callback' ], $key, $product_tab );
        }
 
        echo '</div>';
    } 
}

The result was as follows:

  1. All the tabs have lost titles.
  2. Now tabs are shown after woocommerce_share hook and in their old place. They are just copied.

Question:

  1. How do I fix the code to show the tab titles?
  2. How to fix the code so that the tabs are shown only after the woocommerce_share hook?

I would be glad to have your help!

7uc1f3r
  • 28,449
  • 17
  • 32
  • 50
Dmitry
  • 119
  • 1
  • 9
  • 38

1 Answers1

1

First of all, I've slightly updated your existing code, to more recent version:

// You can use add_meta_boxes_{post_type} for best practice, so your hook will only run when editing a specific post type. This will only receive 1 parameter – $post
function action_add_meta_boxes_product( $post ) {
    add_meta_box( 
        'add_product_metabox_additional_tabs',
        __( 'Additional product Tabs', 'woocommerce' ),
        'additional_product_tabs_metabox_content',
        'product',
        'normal',
        'high'
    );
}
add_action( 'add_meta_boxes_product', 'action_add_meta_boxes_product', 10, 1 );

//  Add custom metabox content
function additional_product_tabs_metabox_content( $post ) {
    // Shipping
    echo '<h4>' . __( 'Shipping', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_shipping', true );
    wp_editor( $value, '_custom_shipping', array( 'editor_height' => 100 ) );

    // Color
    echo '<br><hr><h4>' . __( 'Color', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_color', true );
    wp_editor( $value, '_custom_color', array( 'editor_height' => 100 ) );

    // Material
    echo '<br><hr><h4>' . __( 'Material', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_material', true );
    wp_editor( $value, '_custom_material', array( 'editor_height' => 100 ) );

    // Size
    echo '<br><hr><h4>' . __( 'Size', 'woocommerce' ) . '</h4>';
    $value = get_post_meta( $post->ID, '_custom_size', true );
    wp_editor( $value, '_custom_size', array( 'editor_height' => 100 ) );

    // Nonce field (for security)
    echo '<input type="hidden" name="additional_product_tabs_nonce" value="' . wp_create_nonce() . '">';
}

// Save product data
function action_save_post_product( $post_id, $post, $update ) {
    // Security check
    if ( ! isset( $_POST[ 'additional_product_tabs_nonce' ] ) ) {
        return $post_id;
    }

    // Verify that the nonce is valid.
    if ( ! wp_verify_nonce( $_POST[ 'additional_product_tabs_nonce' ] ) ) {
        return $post_id;
    }

    // If this is an autosave, our form has not been submitted, so we don't want to do anything
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return $post_id;
    }

    if ( ! current_user_can( 'edit_product', $post_id ) ) {
        return $post_id;
    }

    // Sanitize user input and save the post meta fields values
    if ( isset( $_POST[ '_custom_shipping' ] ) )
        update_post_meta( $post_id, '_custom_shipping', wp_kses_post( $_POST[ '_custom_shipping' ] ) );

    if ( isset( $_POST[ '_custom_color' ] ) )
        update_post_meta( $post_id, '_custom_color', wp_kses_post( $_POST[ '_custom_color' ] ) );

    if ( isset( $_POST[ '_custom_material' ] ) )
        update_post_meta( $post_id, '_custom_material', wp_kses_post( $_POST[ '_custom_material' ] ) );

    if ( isset( $_POST[ '_custom_size' ] ) )
        update_post_meta( $post_id, '_custom_size', wp_kses_post( $_POST[ '_custom_size' ] ) );
}
add_action( 'save_post_product', 'action_save_post_product', 10, 3 );

Then your biggest mistake is using $product_tabs = apply_filters( 'woocommerce_product_tabs', array() );. This is because not only your call is executed but also the default call of WooCommerce. That's why these are shown twice.

The solution is to simply add your custom tabs via an array that is separate from the default WooCommerce functionality.

So you get:

// Removing DEFAULT tabs
function filter_woocommerce_product_tabs( $tabs ) {
    // Remove the description tab
    unset( $tabs['description'] );

    // Remove the additional information tab
    unset( $tabs['additional_information'] );

    return $tabs;
}
add_filter( 'woocommerce_product_tabs', 'filter_woocommerce_product_tabs', 100, 1 );

function my_custom_tabs() {
    // Initialize
    $tabs = array();

    // Adds Shipping Tab
    $tabs['custom_shipping_tab'] = array(
        'title'     => __( 'Shipping', 'woocommerce' ),
        'priority'  => 10,
        'callback'  => 'woo_custom_shipping_tab_content'
    );

    // Adds Color Tab
    $tabs['custom_color_tab'] = array(
        'title'     => __( 'Color', 'woocommerce' ),
        'priority'  => 20,
        'callback'  => 'woo_custom_color_tab_content'
    );

    // Adds Material Tab
    $tabs['custom_material_tab'] = array(
        'title'     => __( 'Material', 'woocommerce' ),
        'priority'  => 30,
        'callback'  => 'woo_custom_material_tab_content'
    );

    // Adds Size Tab
    $tabs['custom_size_tab'] = array(
        'title'     => __( 'Size', 'woocommerce' ),
        'priority'  => 40,
        'callback'  => 'woo_custom_size_tab_content'
    );

    return $tabs;
}  

function woo_custom_shipping_tab_content() {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_shipping' ) . '</p></div>';
}

function woo_custom_color_tab_content()  {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_color' ) . '</p></div>';
}

function woo_custom_material_tab_content()  {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_material' ) . '</p></div>';
}

function woo_custom_size_tab_content()  {
    global $product;

    echo'<div><p>'. $product->get_meta( '_custom_size' ) . '</p></div>';
}

function action_woocommerce_share() {
    // Call your custom tabs
    $product_tabs = my_custom_tabs();

    // NOT empty
    if ( ! empty( $product_tabs ) ) : ?>

        <div class="woocommerce-tabs wc-tabs-wrapper">
            <ul class="tabs wc-tabs" role="tablist">
                <?php foreach ( $product_tabs as $key => $product_tab ) : ?>
                    <li class="<?php echo esc_attr( $key ); ?>_tab" id="tab-title-<?php echo esc_attr( $key ); ?>" role="tab" aria-controls="tab-<?php echo esc_attr( $key ); ?>">
                        <a href="#tab-<?php echo esc_attr( $key ); ?>">
                            <?php echo wp_kses_post( apply_filters( 'woocommerce_product_' . $key . '_tab_title', $product_tab['title'], $key ) ); ?>
                        </a>
                    </li>
                <?php endforeach; ?>
            </ul>
            <?php foreach ( $product_tabs as $key => $product_tab ) : ?>
                <div class="woocommerce-Tabs-panel woocommerce-Tabs-panel--<?php echo esc_attr( $key ); ?> panel entry-content wc-tab" id="tab-<?php echo esc_attr( $key ); ?>" role="tabpanel" aria-labelledby="tab-title-<?php echo esc_attr( $key ); ?>">
                    <?php
                    if ( isset( $product_tab['callback'] ) ) {
                        call_user_func( $product_tab['callback'], $key, $product_tab );
                    }
                    ?>
                </div>
            <?php endforeach; ?>

            <?php do_action( 'woocommerce_product_after_tabs' ); ?>
        </div>

    <?php endif;
}
add_action( 'woocommerce_share', 'action_woocommerce_share' );

Note: displaying the tabs horizontally or vertically is then a matter of applying CSS, this is theme related. Optionally you can add extra classes to the output of these tabs.

7uc1f3r
  • 28,449
  • 17
  • 32
  • 50