(int) $o['id'],
'label' => (string) $o['label'],
'price' => (float) $o['price_delta'],
'premium' => ! empty( $o['exclude_from_allowance'] ),
'default' => ! empty( $o['default_selected'] ),
'available' => ! empty( $o['available'] ),
);
}
$groups[] = array(
'id' => (int) $g['id'],
'name' => (string) $g['name'],
'select_type' => (string) $g['select_type'],
'min' => (int) $g['min_select'],
'max' => (int) $g['max_select'],
'included_free' => (int) $g['included_free'],
'free_policy' => (string) $g['free_policy'],
'description' => (string) $g['description'],
'assignment_id' => (int) $g['assignment_id'],
'options' => $options,
);
}
$product = wc_get_product( (int) $product_id );
$base_price = $product ? (float) wc_get_price_to_display( $product, array( 'price' => $product->get_price() ) ) : 0.0;
return array(
'product_id' => (int) $product_id,
'base_price' => $base_price,
'currency' => function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '',
'groups' => $groups,
'rules' => isset( $cfg['rules'] ) ? $cfg['rules'] : array(),
);
}
public function enqueue_assets() {
if ( ! function_exists( 'is_product' ) || ! is_product() ) { return; }
global $product;
$pid = $product instanceof WC_Product ? $product->get_id() : ( function_exists( 'get_the_ID' ) ? (int) get_the_ID() : 0 );
if ( ! self::config_for_product( $pid ) ) { return; }
$base = defined( 'AIEO_DIR' ) ? AIEO_DIR : '';
$jrel = 'assets/js/aieo-option-groups-frontend.js';
$crel = 'assets/css/aieo-option-groups.css';
$jver = ( $base && file_exists( $base . $jrel ) ) ? (string) filemtime( $base . $jrel ) : '1.0';
$cver = ( $base && file_exists( $base . $crel ) ) ? (string) filemtime( $base . $crel ) : '1.0';
wp_enqueue_style( 'aieo-option-groups', plugins_url( $crel, AIEO_FILE ), array(), $cver );
wp_enqueue_script( 'aieo-option-groups-frontend', plugins_url( $jrel, AIEO_FILE ), array( 'jquery' ), $jver, true );
wp_localize_script( 'aieo-option-groups-frontend', 'aieoOG', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'i18n' => array(
'chooseMin' => __( 'Choose at least %1$d for “%2$s”.', 'ai-eshop-optimizer' ),
'chooseMax' => __( 'Choose at most %1$d for “%2$s”.', 'ai-eshop-optimizer' ),
'soldOut' => __( 'Sold out', 'ai-eshop-optimizer' ),
'free' => __( 'free', 'ai-eshop-optimizer' ),
),
) );
}
public function render_picker() {
global $product;
$pid = $product instanceof WC_Product ? $product->get_id() : 0;
$cfg = $pid ? self::config_for_product( $pid ) : null;
if ( ! $cfg ) { return; }
$cur = $cfg['currency'];
echo '
';
foreach ( $cfg['groups'] as $g ) {
$type = 'radio' === $g['select_type'] ? 'radio' : 'checkbox';
$req = $g['min'] > 0;
$hint = self::group_hint( $g );
echo '
';
}
echo '';
echo '
';
}
private static function group_hint( $g ) {
$bits = array();
if ( $g['min'] > 0 && $g['min'] === $g['max'] ) {
$bits[] = sprintf( _n( 'choose %d option', 'choose %d options', $g['min'], 'ai-eshop-optimizer' ), $g['min'] );
} else {
if ( $g['min'] > 0 ) { $bits[] = sprintf( __( 'min %d', 'ai-eshop-optimizer' ), $g['min'] ); }
if ( $g['max'] > 0 ) { $bits[] = sprintf( __( 'up to %d', 'ai-eshop-optimizer' ), $g['max'] ); }
}
if ( $g['included_free'] > 0 ) { $bits[] = sprintf( __( '%d free', 'ai-eshop-optimizer' ), $g['included_free'] ); }
return $bits ? '(' . implode( ', ', $bits ) . ')' : '';
}
private static function price_label( $delta, $cur ) {
if ( abs( $delta ) < 0.00001 ) { return ''; }
$sign = $delta > 0 ? '+' : '−';
return $sign . $cur . number_format_i18n( abs( $delta ), 2 );
}
private static function posted_selection() {
if ( empty( $_POST[ self::FORM_FIELD ] ) ) { return array(); }
$raw = (array) wp_unslash( $_POST[ self::FORM_FIELD ] );
return array_values( array_unique( array_filter( array_map( 'intval', $raw ) ) ) );
}
public function validate_add( $passed, $product_id, $qty ) {
$cfg = self::config_for_product( $product_id );
if ( ! $cfg ) { return $passed; }
$res = AIEO_Option_Groups_Pricing::resolve( AIEO_Option_Groups_Store::get_product_config( $product_id ), self::posted_selection() );
if ( ! $res['valid'] ) {
foreach ( $res['errors'] as $err ) { wc_add_notice( $err, 'error' ); }
return false;
}
return $passed;
}
public function add_cart_item_data( $data, $product_id, $variation_id ) {
$cfg = self::config_for_product( $product_id );
if ( ! $cfg ) { return $data; }
$selected = self::posted_selection();
$store = AIEO_Option_Groups_Store::get_product_config( $product_id );
$res = AIEO_Option_Groups_Pricing::resolve( $store, $selected );
if ( ! $res['valid'] ) { return $data; }
$data['aieo_og'] = array(
'options' => $selected,
'total_delta' => (float) $res['total_delta'],
'lines' => $res['lines'],
);
$data['aieo_og_sig'] = md5( wp_json_encode( $selected ) );
return $data;
}
public function get_cart_item_from_session( $item, $values ) {
if ( isset( $values['aieo_og'] ) ) { $item['aieo_og'] = $values['aieo_og']; }
return $item;
}
public function before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return; }
if ( ! $cart || ! method_exists( $cart, 'get_cart' ) ) { return; }
foreach ( $cart->get_cart() as $item ) {
if ( empty( $item['aieo_og'] ) || empty( $item['data'] ) ) { continue; }
$product = $item['data'];
$base = (float) $product->get_price( 'edit' );
$product->set_price( $base + (float) $item['aieo_og']['total_delta'] );
}
}
public function get_item_data( $item_data, $cart_item ) {
if ( empty( $cart_item['aieo_og']['lines'] ) ) { return $item_data; }
$cur = function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '';
foreach ( $cart_item['aieo_og']['lines'] as $line ) {
$val = $line['label'];
if ( ! empty( $line['free'] ) ) {
$val .= ' (' . __( 'free', 'ai-eshop-optimizer' ) . ')';
} elseif ( abs( (float) $line['charged_delta'] ) > 0.00001 ) {
$val .= ' (+' . $cur . number_format_i18n( (float) $line['charged_delta'], 2 ) . ')';
}
$item_data[] = array(
'key' => __( 'Option', 'ai-eshop-optimizer' ),
'value' => $val,
'display' => $val,
);
}
return $item_data;
}
public function add_order_line_meta( $item, $cart_item_key, $values, $order ) {
if ( empty( $values['aieo_og']['lines'] ) ) { return; }
$cur = function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '';
foreach ( $values['aieo_og']['lines'] as $line ) {
$val = $line['label'];
if ( empty( $line['free'] ) && abs( (float) $line['charged_delta'] ) > 0.00001 ) {
$val .= ' (+' . $cur . number_format_i18n( (float) $line['charged_delta'], 2 ) . ')';
} elseif ( ! empty( $line['free'] ) ) {
$val .= ' (' . __( 'free', 'ai-eshop-optimizer' ) . ')';
}
$item->add_meta_data( $line['label'] , $val, false );
}
$item->add_meta_data( '_aieo_og_options', $values['aieo_og']['options'], true );
}
public function ajax_resolve() {
$pid = isset( $_POST['product_id'] ) ? (int) $_POST['product_id'] : 0;
$sel = isset( $_POST['options'] ) ? array_map( 'intval', (array) wp_unslash( $_POST['options'] ) ) : array();
$cfg = $pid ? self::config_for_product( $pid ) : null;
if ( ! $cfg ) { wp_send_json_error(); }
$res = AIEO_Option_Groups_Pricing::resolve( AIEO_Option_Groups_Store::get_product_config( $pid ), $sel );
wp_send_json_success( array(
'base_price' => $cfg['base_price'],
'total_delta' => $res['total_delta'],
'total' => $cfg['base_price'] + $res['total_delta'],
'valid' => $res['valid'],
'errors' => $res['errors'],
'lines' => $res['lines'],
) );
}
}