Vertical and expanded product tabs in WooCommerce - php

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:
All the tabs have lost titles.
Now tabs are shown after woocommerce_share hook and in their old place. They are just copied.
Question:
How do I fix the code to show the tab titles?
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!

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.

Related

Disable tab on product page if it has no added WooCommerce products

I am using code that displays the Related Products tab on a single product page.
// Display a multiselect field in "Linked Products" section
add_action( 'woocommerce_product_options_related', 'display_handles_product_field' );
function display_handles_product_field() {
global $product_object, $post;
?>
<h2><strong>Related products in tabs</strong></h2>
<p class="form-field">
<label for="handles_product"><?php _e( 'Related products', 'woocommerce' ); ?></label>
<select class="wc-product-search" multiple="multiple" id="handles_product_ids" name="_handles_product_ids[]" data-placeholder="<?php esc_attr_e( 'Search for a product…', 'woocommerce' ); ?>" data-action="woocommerce_json_search_products_and_variations" data-exclude="<?php echo intval( $post->ID ); ?>">
<?php
$product_ids = $product_object->get_meta( '_handles_product_ids' );
foreach ( $product_ids as $product_id ) {
$product = wc_get_product( $product_id );
if ( is_object( $product ) ) {
echo '<option value="' . esc_attr( $product_id ) . '"' . selected( true, true, false ) . '>' . wp_kses_post( $product->get_formatted_name() ) . '</option>';
}
}
?>
</select>
</p>
<?php
}
// Save the values to the product
add_action( 'woocommerce_admin_process_product_object', 'save_handles_product_field_value', 10, 1 );
function save_handles_product_field_value( $product ){
$data = isset( $_POST['_handles_product_ids'] ) ? array_map( 'intval', (array) $_POST['_handles_product_ids'] ) : array();
$product->update_meta_data( '_handles_product_ids', $data );
}
/* New Handles Product Tab */
add_filter( 'woocommerce_product_tabs', 'new_handles_product_tab' );
function new_handles_product_tab( $tabs ) {
/* Add new tab */
$tabs['new_handles_product_tab'] = array(
'title' => __( 'Related products', 'woocommerce' ),
'priority' => 50,
'callback' => 'new_handles_product_tab_content'
);
return $tabs;
}
function new_handles_product_tab_content() {
global $product;
$product_ids = $product->get_meta( '_handles_product_ids' ); // Get handles
if( ! empty($product_ids) )
$product_ids = implode(',', $product_ids);
echo do_shortcode( "[products ids='$product_ids' columns='4']" ); // Using [products] shortcode for display.
}
The code is working, but there is a small problem. If there are no manually added products in the "Related" tab, then all products of the store are displayed.
Tell me how you can fix this? How can I disable a tab if there are no added products in it?
I will be glad for your help!
You can use the same condition that you added in the new_handles_product_tab_content function. Only add tab if products found.
/* New Handles Product Tab */
add_filter( 'woocommerce_product_tabs', 'new_handles_product_tab' );
function new_handles_product_tab( $tabs ) {
global $product;
$product_ids = $product->get_meta( '_handles_product_ids' ); // Get handles
if( ! empty($product_ids) ){
/* Add new tab */
$tabs['new_handles_product_tab'] = array(
'title' => __( 'Related products', 'woocommerce' ),
'priority' => 50,
'callback' => 'new_handles_product_tab_content'
);
}
return $tabs;
}

Display custom field values of product variations to custom product tab in WooCommerce

I successfully created a 3 custom field for each product variation and it's properly working (saving, updating).
For this I use the following code:
/* Add custom field input # Product Data > Variations > Single Variation */
add_action( 'woocommerce_variation_options', 'add_custom_field_cage_code_to_variations', 10, 3 );
function add_custom_field_cage_code_to_variations( $loop, $variation_data, $variation ) {
echo '<div class="cage_code_options_group options_group">';
woocommerce_wp_text_input( array(
'id' => 'cage_code[' . $loop . ']',
'class' => 'short',
'label' => __( 'Cage Code', 'magazine' ),
'wrapper_class' => 'form-field form-row form-row-first',
'value' => get_post_meta( $variation->ID, 'cage_code', true )
));
woocommerce_wp_text_input( array(
'id' => 'cage_code_part_number[' . $loop . ']',
'class' => 'short',
'label' => __( 'Cage Code - Part #', 'magazine' ),
'wrapper_class' => 'form-field form-row form-row-last',
'value' => get_post_meta( $variation->ID, 'cage_code_part_number', true )
));
woocommerce_wp_text_input( array(
'id' => 'cage_code_niin_nsn_number[' . $loop . ']',
'class' => 'short',
'label' => __( 'NIIN/NSN Number', 'magazine' ),
'wrapper_class' => 'form-field form-row form-row-first',
'value' => get_post_meta( $variation->ID, 'cage_code_niin_nsn_number', true )
));
echo '</div>';
}
/* Save custom field on product variation save */
add_action( 'woocommerce_save_product_variation', 'magazine_save_custom_field_variations', 10, 2 );
function magazine_save_custom_field_variations( $variation_id, $i ) {
$cage_code = $_POST['cage_code'][$i];
if ( isset( $cage_code ) ) update_post_meta( $variation_id, 'cage_code', esc_attr( $cage_code ) );
$cage_code_part_number = $_POST['cage_code_part_number'][$i];
if ( isset( $cage_code ) ) update_post_meta( $variation_id, 'cage_code_part_number', esc_attr( $cage_code_part_number ) );
$cage_code_niin_nsn_number = $_POST['cage_code_niin_nsn_number'][$i];
if ( isset( $cage_code_niin_nsn_number ) ) update_post_meta( $variation_id, 'cage_code_niin_nsn_number', esc_attr( $cage_code_niin_nsn_number ) );
}
Then I created a new product tab:
// Add a custom product data tab
add_filter( 'woocommerce_product_tabs', 'woo_cage_code_info_tab' );
function woo_cage_code_info_tab( $tabs ) {
// Adds the new tab
$tabs['cage_code_information_tab'] = array(
'title' => __( 'Cage Code Information', 'woocommerce' ),
'priority' => 50,
'callback' => 'woo_cage_code_info_tab_content'
);
return $tabs;
}
function woo_cage_code_info_tab_content() {
?>
<script type="text/template" id="tmpl-variation-template">
<div class="woocommerce-variation-cage-code">
{{{ data.variation.cage_code}}}
</div>
</script>
<?php
}
My problem
The custom fields are not displaying on the new product tab I created. I tried to use this code. As applied in next tutorial and put it inside the product tab.
<script type="text/template" id="tmpl-variation-template">
<div class="woocommerce-variation-cage-code">
{{{ data.variation.custom_field}}}
</div>
</script>
But the data is displaying in the variable section (above add to cart button).
My question
Is there a way to display the custom fields inside the new product tab that will change the value when select dropdown variable is changed like the data on 'Additional Information' Tab?
In your callback function you could use the following
The display/output is updated accordingly with the dropdown select menu for variable products
function woo_cage_code_info_tab_content() {
global $product;
if ( $product->is_type( 'variable' ) ) {
// Loop through the variation IDs
foreach( $product->get_children() as $key => $variation_id ) {
// Get an instance of the WC_Product_Variation Object
$variation = wc_get_product( $variation_id );
// Get meta
$cage_code = $variation->get_meta( 'cage_code' );
$cage_code_part_number = $variation->get_meta( 'cage_code_part_number' );
$cage_code_niin_nsn_number = $variation->get_meta( 'cage_code_niin_nsn_number' );
// Output
echo '<div class="woo_cage_code_info_tab_content woo_cage_code_info_tab_content-' . $variation_id .'">';
if ( $cage_code ) {
echo '<p>Cage code: ' . $cage_code . '</p>';
}
if ( $cage_code_part_number ) {
echo '<p>Cage code part number: ' . $cage_code_part_number . '</p>';
}
if ( $cage_code_niin_nsn_number ) {
echo '<p>Cage code niin nsn_number: ' . $cage_code_niin_nsn_number . '</p>';
}
echo '</div>';
}
?>
<script>
jQuery(document).ready(function($) {
// Hide all
$( '.woo_cage_code_info_tab_content' ).css( 'display', 'none' );
// Change
$( 'input.variation_id' ).change( function() {
// Hide all
$( '.woo_cage_code_info_tab_content' ).css( 'display', 'none' );
if( $( 'input.variation_id' ).val() != '' ) {
var var_id = $( 'input.variation_id' ).val();
// Display current
$( '.woo_cage_code_info_tab_content-' + var_id ).css( 'display', 'block' );
}
});
});
</script>
<?php
}
}

WooCommerce Variations Table

I have a variable Table, that I need to show stock levels per location - and not the total stock for each product - as it currently is.
The plugin used: Woocommerce Variations to Table - Grid
Added the fields in the variation by the functions.php method
below is the code that the Variations Table Grid use to show the stock number.
<?php
if ($vartable_stock == 1) {
if (absint($vartable_low_stock_thresh) > 0 && $varstock < absint($vartable_low_stock_thresh) && get_post_meta($value['variation_id'], '_manage_stock', true) == 'yes' ) {
$allcolumns['vartable_stock'] = '<td class="stockcol" data-label="'. apply_filters('vartable_dl_stock', $headenames['vartable_stock'], $value) .'">'. (get_post_meta($value['variation_id'], '_stock_status', true) != 'outofstock' && $varstock > 0 ? '<span class="lowstock">'. str_replace ('%n', $varstock, __($vartable_low_stock_text, 'vartable')) .'</span>' : '<span class="outofstock">'.__($vartable_out_stock_text, 'vartable').'</span>') .'</td>';
} else {
$allcolumns['vartable_stock'] = '<td class="stockcol" data-label="'. apply_filters('vartable_dl_stock', $headenames['vartable_stock'], $value) .'">'. (get_post_meta($value['variation_id'], '_stock_status', true) != 'outofstock' ? '<span class="instock">'. str_replace ('%n', $varstock, __($vartable_in_stock_text, 'vartable')) .'</span>' : '<span class="outofstock">'.__($vartable_out_stock_text, 'vartable').'</span>') .'</td>';
}
}
?>
This shows the Stock Levels for each variation as seen in the image below.
Here is what it looks like in the backend of the product:
Here is the code that I used for adding those four custom fields into the product variation.
// 1. Add custom field input # Product Data > Variations > Single Variation
add_action( 'woocommerce_variation_options_pricing', 'stock_warehouse_add_custom_field_to_variations', 10, 3 );
// Durban Stock Number
function stock_warehouse_add_custom_field_to_variations( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input( array(
'id' => 'stock_level_durban[' . $loop . ']',
'class' => 'short',
'label' => __( 'Durban Stock', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, 'stock_level_durban', true )
)
);
// Cape Town Stock Number
woocommerce_wp_text_input( array(
'id' => 'stock_level_cape_town[' . $loop . ']',
'class' => 'short',
'label' => __( 'Cape Town Stock', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, 'stock_level_cape_town', true )
)
);
// PE Stock Number
woocommerce_wp_text_input( array(
'id' => 'stock_level_pe[' . $loop . ']',
'class' => 'short',
'label' => __( 'Port Elizabeth Stock', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, 'stock_level_pe', true )
)
);
// JHB Stock Number
woocommerce_wp_text_input( array(
'id' => 'stock_level_jhb[' . $loop . ']',
'class' => 'short',
'label' => __( 'JHB Stock', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, 'stock_level_jhb', true )
)
);
}
// -----------------------------------------
// 2. Save custom field on product variation save
add_action( 'woocommerce_save_product_variation', 'stock_warehouse_save_custom_field_to_variations', 10, 2 );
function stock_warehouse_save_custom_field_to_variations( $variation_id, $i ) {
$stock_level_durban = $_POST['stock_level_durban'][$i];
if ( isset( $stock_level_durban ) ) update_post_meta( $variation_id, 'stock_level_durban', esc_attr( $stock_level_durban ) );
$stock_level_cape_town = $_POST['stock_level_cape_town'][$i];
if ( isset( $stock_level_cape_town ) ) update_post_meta( $variation_id, 'stock_level_cape_town', esc_attr( $stock_level_cape_town ) );
$stock_level_pe = $_POST['stock_level_pe'][$i];
if ( isset( $stock_level_pe ) ) update_post_meta( $variation_id, 'stock_level_pe', esc_attr( $stock_level_pe ) );
$stock_level_jhb = $_POST['stock_level_jhb'][$i];
if ( isset( $stock_level_jhb) ) update_post_meta( $variation_id, 'stock_level_jhb', esc_attr( $stock_level_jhb) );
}
// -----------------------------------------
// 3. Store custom field value into variation data
add_filter( 'woocommerce_available_variation', 'stock_warehouse_add_custom_field_variation_data' );
function stock_warehouse_add_custom_field_variation_data( $variations ) {
$variations['stock_level_durban'] = '<div class="woocommerce_custom_field">Durban Stock: <span>' . get_post_meta( $variations[ 'variation_id' ], 'stock_level_durban', true ) . '</span></div>';
$variations['stock_level_cape_town'] = '<div class="woocommerce_custom_field">Cape Town Stock: <span>' . get_post_meta( $variations[ 'variation_id' ], 'stock_level_cape_town', true ) . '</span></div>';
$variations['stock_level_pe'] = '<div class="woocommerce_custom_field">PE Stock: <span>' . get_post_meta( $variations[ 'variation_id' ], 'stock_level_pe', true ) . '</span></div>';
$variations['stock_level_jhb'] = '<div class="woocommerce_custom_field">JHB Stock: <span>' . get_post_meta( $variations[ 'variation_id' ], 'stock_level_jhb', true ) . '</span></div>';
return $variations;
}
function woo_hide_product_categories_widget( $list_args ){
$list_args[ 'hide_empty' ] = 1;
return $list_args;
}
add_filter( 'woocommerce_product_categories_widget_args', 'woo_hide_product_categories_widget' );
add_filter( 'get_terms', 'get_subcategory_terms', 10, 3 );
function get_subcategory_terms( $terms, $taxonomies, $args ) {
$new_terms = array();
// if a product category and on the shop page
if ( in_array( 'product_cat', $taxonomies ) && ! is_admin() ) {
foreach ( $terms as $key => $term ) {
if ( ! in_array( $term->slug, array( 'uncategorized' ) ) ) {
$new_terms[] = $term;
}
}
$terms = $new_terms;
}
return $terms;
}
add_filter( 'woocommerce_product_add_to_cart_text', function( $text ) {
global $product;
if ( $product->is_type( 'variable' ) ) {
$text = $product->is_purchasable() ? __( 'View', 'woocommerce' ) : __( 'View', 'woocommerce' );
}
return $text;
}, 10 );
add_filter( 'woocommerce_attribute_label', 'rename_color_attribute_label', 10, 3);
function rename_color_attribute_label($label, $name, $product){
if(strtolower($label)=='colour'){
$label = 'Variant';
}
return $label;
}
I am trying to get the SOH to show like 0/0/0/28 instead of just the total "28" so that customers can see where the stock is located and not just the total amount.

Custom metabox content displayed in single product additional tabs on Woocommerce

Thanks to these two posts I have come up with this solution for adding multiple tabs to Woocommerce product detail page.
Editing Custom product tab content in Woocommerce Admin product pages
Adding multiple tabs to WooCommerce single product pages
However, I am still having trouble saving the data and can't figure out how to make each meta_box save. I thought of a foreach statement but I'm not that well versed in PHP to know how the syntax is.
Here is my code. I have 6 tabs I added which show up on the page, and the meta boxes show up in the admin panel but they won't save any input. I only have one that is trying to save right now and I feel like the problem is in the save function.
add_action( 'add_meta_boxes', 'create_custom_meta_box' );
if ( ! function_exists( 'create_custom_meta_box' ) )
{
function create_custom_meta_box()
{
add_meta_box(
'custom_product_cost_field',
__( 'Cost and Performance Tab', 'woocommerce' ),
'add_custom_content_meta_box',
'product',
'normal',
'high'
);
add_meta_box(
'custom_product_environment_field',
__( 'Environment Tab', 'woocommerce' ),
'add_custom_content_meta_box',
'product',
'normal',
'high'
);
add_meta_box(
'custom_product_dilution_field',
__( 'Dilution Directions Tab', 'woocommerce' ),
'add_custom_content_meta_box',
'product',
'normal',
'high'
);
add_meta_box(
'custom_product_packaging_field',
__( 'Packaging and Handling', 'woocommerce' ),
'add_custom_content_meta_box',
'product',
'normal',
'high'
);
add_meta_box(
'custom_product_application_field',
__( 'Use and Application Tab', 'woocommerce' ),
'add_custom_content_meta_box',
'product',
'normal',
'high'
);
add_meta_box(
'custom_product_specification_field',
__( 'Product Specification Tab', 'woocommerce' ),
'add_custom_content_meta_box',
'product',
'normal',
'high'
);
}
}
// Custom metabox content in admin product pages
if ( ! function_exists( 'add_custom_content_meta_box' ) )
{
function add_custom_content_meta_box( $post )
{
$value = get_post_meta( $post->ID, 'cost_performance_tab', true ) ? get_post_meta( $post->ID, 'cost_performance_tab', true ) : '';
wp_editor( $value, 'custom_cost_performance_tab', array( 'editor_height' => 100 ) );
echo '<input type="hidden" name="custom_product_field_nonce" value="' . wp_create_nonce() . '">';
}
}
//Save the data of the Meta field
add_action( 'save_post', 'save_custom_content_meta_box', 10, 1 );
if ( ! function_exists( 'save_custom_content_meta_box' ) )
{
function save_custom_content_meta_box( $post_id ) {
// We need to verify this with the proper authorization (security stuff).
// Check if our nonce is set.
if ( ! isset( $_POST[ 'custom_product_field_nonce' ] ) ) {
return $post_id;
}
$nonce = $_REQUEST[ 'custom_product_field_nonce' ];
//Verify that the nonce is valid.
if ( ! wp_verify_nonce( $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;
}
// Check the user's permissions.
if ( 'page' == $_POST[ 'post_type' ] ) {
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return $post_id;
}
} else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
}
// --- Its safe for us to save the data ! --- //
// Sanitize user input and update the meta field in the database.
update_post_meta( $post_id, 'cost_performance_tab', wp_kses_post($_POST[ 'custom_cost_performance_tab' ]) );
}
}
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['reviews'] ); // Remove the reviews tab
unset( $tabs['additional_information'] ); // Remove the additional information tab
// 2 Adding new tabs and set the right order
//Attribute Cost and Performance tab
$tabs['cost_performance_tab'] = array(
'title' => __( 'Cost + Performance', 'woocommerce' ),
'priority' => 100,
'callback' => 'woo_cost_performance_tab_content'
);
// Adds the environment tab
$tabs['environment_tab'] = array(
'title' => __( 'Environment', 'woocommerce' ),
'priority' => 110,
'callback' => 'woo_environment_tab_content'
);
// Adds the dilution tab
$tabs['dilution_tab'] = array(
'title' => __( 'Suggested Dilution Directions', 'woocommerce' ),
'priority' => 120,
'callback' => 'woo_dilution_tab_content'
);
// Adds the packaging tab
$tabs['packaging_tab'] = array(
'title' => __( 'Packaging + Handling', 'woocommerce' ),
'priority' => 120,
'callback' => 'woo_packaging_tab_content'
);
// Adds the application tab
$tabs['application_tab'] = array(
'title' => __( 'Use + Application', 'woocommerce' ),
'priority' => 120,
'callback' => 'woo_application_tab_content'
);
// Adds the application tab
$tabs['specification_tab'] = array(
'title' => __( 'Product Specification', 'woocommerce' ),
'priority' => 120,
'callback' => 'woo_specification_tab_content'
);
return $tabs;
}
function woo_cost_performance_tab_content() {
// The new tab content
$prod_id = get_the_ID();
echo'<div><p>'.get_post_meta( get_the_ID(), 'cost_performance_tab' ,true ).'</p></div>';
}
function woo_environment_tab_content() {
// The new tab content
$prod_id = get_the_ID();
echo'<div><p>'.get_post_meta( get_the_ID(), 'environment_tab' ,true ).'</p></div>';
}
function woo_dilution_tab_content() {
// The new tab content
$prod_id = get_the_ID();
echo'<div><p>'.get_post_meta( get_the_ID(), 'dilution_tab' ,true ).'</p></div>';
}
function woo_packaging_tab_content() {
// The new tab content
$prod_id = get_the_ID();
echo'<div><p>'.get_post_meta( get_the_ID(), 'packaging_tab' ,true ).'</p></div>';
}
function woo_application_tab_content() {
// The new tab content
$prod_id = get_the_ID();
echo'<div><p>'.get_post_meta( get_the_ID(), 'application_tab' ,true ).'</p></div>';
}
function woo_specification_tab_content() {
// The new tab content
$prod_id = get_the_ID();
echo'<div><p>'.get_post_meta( get_the_ID(), 'specification_tab' ,true ).'</p></div>';
}
You don't need 6 metaboxes in admin product edit pages and there is a lot of mistakes… Try the following instead:
// 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 )
{
// Cost and Performance
echo '<h4>' . __( 'Cost and Performance', 'woocommerce' ) . '</h4>';
$value = get_post_meta( $post->ID, '_cost_performance', true );
wp_editor( $value, '_cost_performance', array( 'editor_height' => 100 ) );
// Environment
echo '<br><hr><h4>' . __( 'Environment', 'woocommerce' ) . '</h4>';
$value = get_post_meta( $post->ID, '_environment', true );
wp_editor( $value, '_environment', array( 'editor_height' => 100 ) );
// Dilution Directions
echo '<br><hr><h4>' . __( 'Dilution Directions', 'woocommerce' ) . '</h4>';
$value = get_post_meta( $post->ID, '_dilution_directions', true );
wp_editor( $value, '_dilution_directions', array( 'editor_height' => 100 ) );
// Environment
echo '<br><hr><h4>' . __( 'Packaging and Handling', 'woocommerce' ) . '</h4>';
$value = get_post_meta( $post->ID, '_packaging_and_handling', true );
wp_editor( $value, '_packaging_and_handling', array( 'editor_height' => 100 ) );
// Use and Application
echo '<br><hr><h4>' . __( 'Use and Application', 'woocommerce' ) . '</h4>';
$value = get_post_meta( $post->ID, '_use_and_application', true );
wp_editor( $value, '_use_and_application', array( 'editor_height' => 100 ) );
// Environment
echo '<br><hr><h4>' . __( 'Specification', 'woocommerce' ) . '</h4>';
$value = get_post_meta( $post->ID, '_specification', true );
wp_editor( $value, '_specification', 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[ '_cost_performance' ]) )
update_post_meta( $post_id, '_cost_performance', wp_kses_post($_POST[ '_cost_performance' ]) );
if( isset($_POST[ '_environment' ]) )
update_post_meta( $post_id, '_environment', wp_kses_post($_POST[ '_environment' ]) );
if( isset($_POST[ '_dilution_directions' ]) )
update_post_meta( $post_id, '_dilution_directions', wp_kses_post($_POST[ '_dilution_directions' ]) );
if( isset($_POST[ '_packaging_and_handling' ]) )
update_post_meta( $post_id, '_packaging_and_handling', wp_kses_post($_POST[ '_packaging_and_handling' ]) );
if( isset($_POST[ '_use_and_application' ]) )
update_post_meta( $post_id, '_use_and_application', wp_kses_post($_POST[ '_use_and_application' ]) );
if( isset($_POST[ '_specification' ]) )
update_post_meta( $post_id, '_specification', wp_kses_post($_POST[ '_specification' ]) );
}
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
//Attribute Cost and Performance tab
$tabs['cost_performance_tab'] = array(
'title' => __( 'Cost + Performance', 'woocommerce' ),
'priority' => 10,
'callback' => 'woo_cost_performance_tab_content'
);
// Adds the environment tab
$tabs['environment_tab'] = array(
'title' => __( 'Environment', 'woocommerce' ),
'priority' => 20,
'callback' => 'woo_environment_tab_content'
);
// Adds the dilution tab
$tabs['dilution_tab'] = array(
'title' => __( 'Suggested Dilution Directions', 'woocommerce' ),
'priority' => 30,
'callback' => 'woo_dilution_tab_content'
);
// Adds the packaging tab
$tabs['packaging_tab'] = array(
'title' => __( 'Packaging + Handling', 'woocommerce' ),
'priority' => 40,
'callback' => 'woo_packaging_tab_content'
);
// Adds the application tab
$tabs['application_tab'] = array(
'title' => __( 'Use + Application', 'woocommerce' ),
'priority' => 60,
'callback' => 'woo_application_tab_content'
);
// Adds the specification tab
$tabs['specification_tab'] = array(
'title' => __( 'Specification', 'woocommerce' ),
'priority' => 70,
'callback' => 'woo_specification_tab_content'
);
$tabs['reviews']['priority'] = 80;
return $tabs;
}
function woo_cost_performance_tab_content() {
global $product;
echo'<div><p>'. $product->get_meta( '_cost_performance' ) . '</p></div>';
}
function woo_environment_tab_content() {
global $product;
echo'<div><p>'. $product->get_meta( '_environment' ) . '</p></div>';
}
function woo_dilution_tab_content() {
global $product;
echo'<div><p>'. $product->get_meta( '_dilution_directions' ) . '</p></div>';
}
function woo_packaging_tab_content() {
global $product;
echo'<div><p>'. $product->get_meta( '_packaging_and_handling' ) . '</p></div>';
}
function woo_application_tab_content() {
global $product;
echo'<div><p>'. $product->get_meta( '_use_and_application' ) . '</p></div>';
}
function woo_specification_tab_content() {
global $product;
echo'<div><p>'. $product->get_meta( '_specification' ) . '</p></div>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and work.

WordPress Redirect Trouble

I'm hoping someone could explain a way to use a variable within the wp_redirect() function? Thanks in advance.
There are two variables:
wp_redirect( $location, $status );
$location is the absolute URI which the user will be redirected to.
$status is the status code to use (eg, 301). Default is 302 (so you can leave it blank if you want).
Your code is not storing value of url and even not getting in add_to_cart_redirect function.Try below code
//* Add/Display Fields
add_action( 'woocommerce_product_options_general_product_data', 'rv_woo_add_custom_general_fields' );
function rv_woo_add_custom_general_fields() {
global $post_id;
global $woocommerce, $post;
echo '<div class="options_group">';
woocommerce_wp_text_input(
array(
'id' => '_rv_woo_product_custom_redirect_url',
'label' => __( 'Redirect on Add to Cart', 'woocommerce' ),
'placeholder' => 'http://',
'desc_tip' => 'true',
'description' => __( 'Enter a URL to redirect the user to after this product is added to the cart.', 'woocommerce' ) ,
'value' => get_post_meta($post_id,'c',true)
)
);
echo '</div>';
}
//* Save Fields
add_action( 'woocommerce_process_product_meta', 'rv_woo_add_custom_general_fields_save' );
function rv_woo_add_custom_general_fields_save( $post_id ){
$rv_woo_redirect_url = get_post_meta($post_id,'c',true);
if( !empty( $rv_woo_redirect_url ) ) {
update_post_meta( $post_id, 'c', esc_url( $rv_woo_redirect_url ) );
}
}
add_filter('add_to_cart_redirect', 'redirect_elsewhere');
function redirect_elsewhere() {
global $woocommerce, $post;
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) );
$rv_woo_redirect_url = get_post_meta($product_id,'c',true);
if( !empty( $rv_woo_redirect_url ) ) {
wp_redirect( $rv_woo_redirect_url );
exit;
}
}

Categories