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
}