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
2026-03-01 13:25:02 +01:00
defined ( 'ABSPATH' ) || exit ;
2025-12-31 00:38:29 +01:00
/**
* Product Data Tab Class
*/
2026-03-01 12:35:02 +01:00
class ProductData {
2026-03-01 13:25:02 +01:00
/**
* Constructor
*/
public function __construct () {
add_filter ( 'woocommerce_product_data_tabs' , array ( $this , 'add_product_data_tab' ) );
add_action ( 'woocommerce_product_data_panels' , array ( $this , 'add_product_data_panel' ) );
add_action ( 'woocommerce_process_product_meta_composable' , array ( $this , 'save_product_data' ) );
add_action ( 'woocommerce_product_options_general_product_data' , array ( $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' ] = array (
'label' => __ ( 'Composable Options' , 'wc-composable-product' ),
'target' => 'composable_product_data' ,
'class' => array ( '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 (
array (
'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' => array (
'min' => '1' ,
'step' => '1' ,
),
)
);
woocommerce_wp_select (
array (
'id' => '_composable_pricing_mode' ,
'label' => __ ( 'Pricing Mode' , 'wc-composable-product' ),
'description' => __ ( 'How to calculate the price.' , 'wc-composable-product' ),
'desc_tip' => true ,
'options' => array (
'' => __ ( 'Use global default' , 'wc-composable-product' ),
'sum' => __ ( 'Sum of selected products' , 'wc-composable-product' ),
'fixed' => __ ( 'Fixed price' , 'wc-composable-product' ),
),
)
);
woocommerce_wp_text_input (
array (
'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' ,
)
);
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
woocommerce_wp_select (
array (
'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' => array (
'' => __ ( '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 ) ? get_post_meta ( $post -> ID , '_composable_include_unpublished' , true ) : '' ,
)
);
woocommerce_wp_select (
array (
'id' => '_composable_criteria_type' ,
'label' => __ ( 'Selection Criteria' , 'wc-composable-product' ),
'description' => __ ( 'How to select available products.' , 'wc-composable-product' ),
'desc_tip' => true ,
'options' => array (
'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 ) ? 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 );
$selected_categories = $selected_categories ? $selected_categories : array ();
$categories = get_terms (
array (
'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 ), 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 );
$selected_tags = $selected_tags ? $selected_tags : array ();
$tags = get_terms (
array (
'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 ), 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 (
array (
'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 ) {
// phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce verified by WooCommerce in woocommerce_process_product_meta.
// 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 );
// 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 );
// 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' ] ) : array ();
update_post_meta ( $post_id , '_composable_categories' , $categories );
// Save tags.
$tags = isset ( $_POST [ '_composable_tags' ] ) ? array_map ( 'absint' , $_POST [ '_composable_tags' ] ) : array ();
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 );
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
2025-12-31 00:38:29 +01:00
}