2025-12-31 00:38:29 +01:00
< ? php
/**
* Product Data Tab
*
2026-03-01 12:35:02 +01:00
* @ package Magdev\WcComposableProduct
2025-12-31 00:38:29 +01:00
*/
2026-03-01 12:35:02 +01:00
namespace Magdev\WcComposableProduct\Admin ;
2025-12-31 00:38:29 +01:00
defined ( 'ABSPATH' ) || exit ;
/**
* Product Data Tab Class
*/
2026-03-01 12:35:02 +01:00
class ProductData {
2025-12-31 00:38:29 +01:00
/**
* Constructor
*/
public function __construct () {
add_filter ( 'woocommerce_product_data_tabs' , [ $this , 'add_product_data_tab' ]);
add_action ( 'woocommerce_product_data_panels' , [ $this , 'add_product_data_panel' ]);
add_action ( 'woocommerce_process_product_meta_composable' , [ $this , 'save_product_data' ]);
add_action ( 'woocommerce_product_options_general_product_data' , [ $this , 'add_general_fields' ]);
}
/**
* Add composable products tab
*
* @ param array $tabs Product data tabs
* @ return array
*/
public function add_product_data_tab ( $tabs ) {
$tabs [ 'composable' ] = [
'label' => __ ( 'Composable Options' , 'wc-composable-product' ),
'target' => 'composable_product_data' ,
'class' => [ 'show_if_composable' ],
'priority' => 21 ,
];
return $tabs ;
}
/**
* Add fields to general tab
*/
public function add_general_fields () {
global $product_object ;
if ( $product_object && $product_object -> get_type () === 'composable' ) {
echo '<div class="options_group show_if_composable">' ;
woocommerce_wp_text_input ([
'id' => '_composable_selection_limit' ,
'label' => __ ( 'Selection Limit' , 'wc-composable-product' ),
'description' => __ ( 'Maximum number of items customers can select. Leave empty to use global default.' , 'wc-composable-product' ),
'desc_tip' => true ,
'type' => 'number' ,
'custom_attributes' => [
'min' => '1' ,
'step' => '1' ,
],
]);
woocommerce_wp_select ([
'id' => '_composable_pricing_mode' ,
'label' => __ ( 'Pricing Mode' , 'wc-composable-product' ),
2025-12-31 21:01:52 +01:00
'description' => __ ( 'How to calculate the price.' , 'wc-composable-product' ),
2025-12-31 00:38:29 +01:00
'desc_tip' => true ,
'options' => [
'' => __ ( 'Use global default' , 'wc-composable-product' ),
'sum' => __ ( 'Sum of selected products' , 'wc-composable-product' ),
'fixed' => __ ( 'Fixed price' , 'wc-composable-product' ),
],
]);
2025-12-31 21:01:52 +01:00
woocommerce_wp_text_input ([
'id' => '_regular_price' ,
'label' => __ ( 'Fixed Price' , 'wc-composable-product' ) . ' (' . get_woocommerce_currency_symbol () . ')' ,
'description' => __ ( 'Enter the fixed price for this composable product.' , 'wc-composable-product' ),
'desc_tip' => true ,
'type' => 'text' ,
'data_type' => 'price' ,
'wrapper_class' => 'composable_fixed_price_field' ,
]);
2025-12-31 00:38:29 +01:00
echo '</div>' ;
}
}
/**
* Add product data panel
*/
public function add_product_data_panel () {
global $post ;
?>
< div id = " composable_product_data " class = " panel woocommerce_options_panel hidden " >
< div class = " options_group " >
< ? php
2026-03-01 12:23:01 +01:00
woocommerce_wp_select ([
'id' => '_composable_include_unpublished' ,
'label' => __ ( 'Include Non-Public Products' , 'wc-composable-product' ),
'description' => __ ( 'Allow draft and private products in the selection. Useful when products should only be sold as part of a composition.' , 'wc-composable-product' ),
'desc_tip' => true ,
'options' => [
'' => __ ( 'Use global default' , 'wc-composable-product' ),
'yes' => __ ( 'Yes' , 'wc-composable-product' ),
'no' => __ ( 'No' , 'wc-composable-product' ),
],
'value' => get_post_meta ( $post -> ID , '_composable_include_unpublished' , true ) ? : '' ,
]);
2025-12-31 00:38:29 +01:00
woocommerce_wp_select ([
'id' => '_composable_criteria_type' ,
'label' => __ ( 'Selection Criteria' , 'wc-composable-product' ),
'description' => __ ( 'How to select available products.' , 'wc-composable-product' ),
'desc_tip' => true ,
'options' => [
'category' => __ ( 'By Category' , 'wc-composable-product' ),
'tag' => __ ( 'By Tag' , 'wc-composable-product' ),
'sku' => __ ( 'By SKU' , 'wc-composable-product' ),
],
'value' => get_post_meta ( $post -> ID , '_composable_criteria_type' , true ) ? : 'category' ,
]);
?>
</ div >
< div class = " options_group composable_criteria_group " id = " composable_criteria_category " >
< p class = " form-field " >
< label for = " _composable_categories " >< ? php esc_html_e ( 'Select Categories' , 'wc-composable-product' ); ?> </label>
< select id = " _composable_categories " name = " _composable_categories[] " class = " wc-enhanced-select " multiple = " multiple " style = " width: 50%; " >
< ? php
$selected_categories = get_post_meta ( $post -> ID , '_composable_categories' , true ) ? : [];
$categories = get_terms ([ 'taxonomy' => 'product_cat' , 'hide_empty' => false ]);
foreach ( $categories as $category ) {
printf (
'<option value="%s" %s>%s</option>' ,
esc_attr ( $category -> term_id ),
selected ( in_array ( $category -> term_id , ( array ) $selected_categories ), true , false ),
esc_html ( $category -> name )
);
}
?>
</ select >
< span class = " description " >< ? php esc_html_e ( 'Select product categories to include.' , 'wc-composable-product' ); ?> </span>
</ p >
</ div >
< div class = " options_group composable_criteria_group " id = " composable_criteria_tag " style = " display: none; " >
< p class = " form-field " >
< label for = " _composable_tags " >< ? php esc_html_e ( 'Select Tags' , 'wc-composable-product' ); ?> </label>
< select id = " _composable_tags " name = " _composable_tags[] " class = " wc-enhanced-select " multiple = " multiple " style = " width: 50%; " >
< ? php
$selected_tags = get_post_meta ( $post -> ID , '_composable_tags' , true ) ? : [];
$tags = get_terms ([ 'taxonomy' => 'product_tag' , 'hide_empty' => false ]);
foreach ( $tags as $tag ) {
printf (
'<option value="%s" %s>%s</option>' ,
esc_attr ( $tag -> term_id ),
selected ( in_array ( $tag -> term_id , ( array ) $selected_tags ), true , false ),
esc_html ( $tag -> name )
);
}
?>
</ select >
< span class = " description " >< ? php esc_html_e ( 'Select product tags to include.' , 'wc-composable-product' ); ?> </span>
</ p >
</ div >
< div class = " options_group composable_criteria_group " id = " composable_criteria_sku " style = " display: none; " >
< ? php
woocommerce_wp_textarea_input ([
'id' => '_composable_skus' ,
'label' => __ ( 'Product SKUs' , 'wc-composable-product' ),
'description' => __ ( 'Enter product SKUs separated by commas.' , 'wc-composable-product' ),
'desc_tip' => true ,
'placeholder' => __ ( 'SKU-1, SKU-2, SKU-3' , 'wc-composable-product' ),
]);
?>
</ div >
</ div >
< ? php
}
/**
* Save product data
*
* @ param int $post_id Post ID
*/
public function save_product_data ( $post_id ) {
// Save selection limit
$selection_limit = isset ( $_POST [ '_composable_selection_limit' ]) ? absint ( $_POST [ '_composable_selection_limit' ]) : '' ;
update_post_meta ( $post_id , '_composable_selection_limit' , $selection_limit );
// Save pricing mode
$pricing_mode = isset ( $_POST [ '_composable_pricing_mode' ]) ? sanitize_text_field ( $_POST [ '_composable_pricing_mode' ]) : '' ;
update_post_meta ( $post_id , '_composable_pricing_mode' , $pricing_mode );
2026-03-01 12:23:01 +01:00
// Save include unpublished
$include_unpublished = isset ( $_POST [ '_composable_include_unpublished' ]) ? sanitize_text_field ( $_POST [ '_composable_include_unpublished' ]) : '' ;
update_post_meta ( $post_id , '_composable_include_unpublished' , $include_unpublished );
2025-12-31 00:38:29 +01:00
// Save criteria type
$criteria_type = isset ( $_POST [ '_composable_criteria_type' ]) ? sanitize_text_field ( $_POST [ '_composable_criteria_type' ]) : 'category' ;
update_post_meta ( $post_id , '_composable_criteria_type' , $criteria_type );
// Save categories
$categories = isset ( $_POST [ '_composable_categories' ]) ? array_map ( 'absint' , $_POST [ '_composable_categories' ]) : [];
update_post_meta ( $post_id , '_composable_categories' , $categories );
// Save tags
$tags = isset ( $_POST [ '_composable_tags' ]) ? array_map ( 'absint' , $_POST [ '_composable_tags' ]) : [];
update_post_meta ( $post_id , '_composable_tags' , $tags );
// Save SKUs
$skus = isset ( $_POST [ '_composable_skus' ]) ? sanitize_textarea_field ( $_POST [ '_composable_skus' ]) : '' ;
update_post_meta ( $post_id , '_composable_skus' , $skus );
}
}