// ── 0. Server-side Add to Cart Handoff (?owl_add_to_cart=PRODUCT_ID&owlb_*...) ────
add_action( 'wp_loaded', function () {
if ( empty( $_GET['owl_add_to_cart'] ) ) return;
header('X-Owl-Handoff-Executed: 1');
$product_id = intval( $_GET['owl_add_to_cart'] );
$design_id = intval( $_GET['owlb_design_id'] ?? 0 );
$qty = max( 1, intval( $_GET['owl_qty'] ?? ( $_GET['owlb_qty'] ?? 1 ) ) );
if ( ! $product_id ) {
wp_redirect( wc_get_cart_url() );
exit;
}
if ( function_exists( 'wc_load_cart' ) && ( ! function_exists( 'WC' ) || ! WC()->cart ) ) {
wc_load_cart();
}
if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
wp_redirect( wc_get_cart_url() );
exit;
}
// Populate $cart_item_data, $_POST and $_REQUEST so all WooCommerce filters capture the design data
$cart_item_data = [];
foreach ( $_GET as $key => $value ) {
$k = (string) $key;
if (
strpos( $k, 'owlb_' ) === 0 ||
strpos( $k, 'badge' ) === 0 ||
strpos( $k, 'form-' ) === 0 ||
strpos( $k, 'addon-' ) === 0 ||
strpos( $k, 'element' ) === 0 ||
strpos( $k, 'panel' ) === 0 ||
strpos( $k, 'section' ) === 0 ||
in_array( $k, [
'step', 'idPatchNote', 'additionalInformation',
'additionalInformationNumber', 'cartItemKey',
], true )
) {
$unslashed = wp_unslash( $value );
$_POST[ $k ] = $unslashed;
$_REQUEST[ $k ] = $unslashed;
$cart_item_data[ $k ] = $unslashed;
}
}
if ( ! empty( $_GET['owlb_price'] ) ) {
$cart_item_data['owlb_price'] = floatval( $_GET['owlb_price'] );
}
$cart_item_data['owlb_unique_key'] = md5( microtime() . ( $design_id ?: rand() ) );
// If editing an existing cart item, remove old item before adding updated design
if ( ! empty( $_GET['replace_cart_item'] ) ) {
$old_key = sanitize_text_field( $_GET['replace_cart_item'] );
if ( isset( WC()->cart->cart_contents[ $old_key ] ) ) {
WC()->cart->remove_cart_item( $old_key );
}
}
$_POST['add-to-cart'] = $product_id;
$_POST['quantity'] = $qty;
$cart_item_key = WC()->cart->add_to_cart( $product_id, $qty, 0, array(), $cart_item_data );
if ( $cart_item_key ) {
wc_add_notice(
sprintf(
__( '“%s” has been added to your cart.', 'woocommerce' ),
get_the_title( $product_id )
),
'success'
);
}
if ( function_exists( 'WC' ) && WC()->session ) {
if ( method_exists( WC()->session, 'set_customer_session_cookie' ) ) {
WC()->session->set_customer_session_cookie( true );
}
if ( method_exists( WC()->session, 'save_data' ) ) {
WC()->session->save_data();
}
}
header( 'X-Owl-Handoff-Executed: 1' );
header( 'X-Owl-Cart-Key: ' . ( $cart_item_key ?: 'FAILED' ) );
header( 'X-Owl-Price-Set: ' . ( $cart_item_data['owlb_price'] ?? 'NONE' ) );
wp_redirect( wc_get_cart_url() );
exit;
}, 5 );
// ── 1. Capture owlb_* / collar-pin / challenge-coin params on add-to-cart ─────
add_filter( 'woocommerce_add_cart_item_data', function( $cart_item_data, $product_id, $variation_id ) {
// Standard owlb_* fields (read from $_GET — sent by the HMAC redirect)
$fields = [
'owlb_design_id' => 'Design ID',
'owlb_token' => 'Token',
'owlb_template' => 'Template',
'owlb_type' => 'Badge Type',
'owlb_size' => 'Size',
'owlb_color' => 'Color',
'owlb_font' => 'Font',
'owlb_text_1' => 'Line 1',
'owlb_text_type_1' => 'Line 1 Type',
'owlb_text_2' => 'Line 2',
'owlb_text_type_2' => 'Line 2 Type',
'owlb_text_3' => 'Line 3',
'owlb_text_type_3' => 'Line 3 Type',
'owlb_text_4' => 'Line 4',
'owlb_text_type_4' => 'Line 4 Type',
'owlb_seal' => 'Seal',
'owlb_attachment' => 'Attachment',
'owlb_colors' => 'Patch Colors',
'owlb_price' => 'Design Price',
'owlb_qty' => 'Quantity',
'owlb_preview_image' => 'Badge Preview',
'owlb_pin_text' => 'Pin Text',
'owlb_pin_text_color' => 'Pin Text Color',
'owlb_pin_text_style' => 'Pin Text Style',
// Collar-pin specific keys (form-collar-* and collarPin*)
'form-collar-text' => 'Pin Text',
'form-collar-text-color' => 'Pin Text Color Hex',
'form-collar-text-color-name' => 'Pin Text Color',
'form-collar-text-style' => 'Pin Text Style',
'form-collar-text-size-label' => 'Pin Text Size',
'form-collar-attachment' => 'Attachment',
'form-collar-image' => 'Collar Preview',
'form-collar-image-wm-off' => 'Collar Preview WM Off',
'collarPinTextPanel' => 'Pin Text',
'collarPinTextColor' => 'Pin Text Color Hex',
'collarPinTextColorName' => 'Pin Text Color Name',
'collarPinTextStyle' => 'Pin Text Style',
'collarPinTextSizeLabel' => 'Pin Text Size Label',
'collarPinAttachment' => 'Collar Attachment',
// Challenge-coin specific keys (form-coin-* primary + coin-* aliases)
'form-coin-front-paneltext1' => 'Front Text Panel 1',
'form-coin-front-paneltext2' => 'Front Text Panel 2',
'form-coin-back-paneltext1' => 'Back Text Panel 1',
'form-coin-back-paneltext2' => 'Back Text Panel 2',
'form-coin-front-panel1-color-name' => 'Front Text Color',
'form-coin-front-panel1-color-code' => 'Front Text Color Code',
'form-coin-front-panel2-color-name' => 'Front Text 2 Color',
'form-coin-front-panel2-color-code' => 'Front Text 2 Color Code',
'form-coin-back-panel1-color-name' => 'Back Text Color',
'form-coin-back-panel1-color-code' => 'Back Text Color Code',
'form-coin-back-panel2-color-name' => 'Back Text 2 Color',
'form-coin-back-panel2-color-code' => 'Back Text 2 Color Code',
'form-coin-front-basecolor-name' => 'Front Base Color',
'form-coin-front-basecolor-code' => 'Front Base Color Code',
'form-coin-back-basecolor-name' => 'Back Base Color',
'form-coin-back-basecolor-code' => 'Back Base Color Code',
'form-coin-front-bordercolor-name' => 'Front Border Color',
'form-coin-front-bordercolor-code' => 'Front Border Color Code',
'form-coin-back-bordercolor-name' => 'Back Border Color',
'form-coin-back-bordercolor-code' => 'Back Border Color Code',
'form-coin-front-bgcolor-name' => 'Front BG Color',
'form-coin-front-bgcolor-code' => 'Front BG Color Code',
'form-coin-back-bgcolor-name' => 'Back BG Color',
'form-coin-back-bgcolor-code' => 'Back BG Color Code',
'form-coin-front-seal-id' => 'Front Seal ID',
'form-coin-back-seal-id' => 'Back Seal ID',
'form-coin-front-seal-image' => 'Front Seal Image',
'form-coin-back-seal-image' => 'Back Seal Image',
'form-coin-front-image' => 'Front Coin Image',
'form-coin-back-image' => 'Back Coin Image',
'form-coin-edges-id' => 'Coin Edge ID',
'form-coin-edges-price' => 'Coin Edge Price',
'form-coin-front-font' => 'Front Text Font',
'form-coin-back-font' => 'Back Text Font',
// coin-* aliases
'coin-front-paneltext1' => 'Front Text 1',
'coin-front-paneltext2' => 'Front Text 2',
'coin-front-top-textcolorname' => 'Front Top Color',
'coin-front-top-textcolorcode' => 'Front Top Color Code',
'coin-front-bottom-textcolorname' => 'Front Bottom Color',
'coin-front-bottom-textcolorcode' => 'Front Bottom Color Code',
'coin-front-basecolorname' => 'Front Base Color',
'coin-front-basecolorcode' => 'Front Base Color Code',
'coin-front-bordercolorname' => 'Front Border Color',
'coin-front-bordercolorcode' => 'Front Border Color Code',
'coin-front-bgcolorname' => 'Front BG Color',
'coin-front-bgcolorcode' => 'Front BG Color Code',
'coin-front-seal-imageid' => 'Front Seal ID',
'coin-front-seal-image' => 'Front Seal Image',
'coin-front-image' => 'Front Coin Image URL',
'coin-front-font' => 'Front Font',
'coin-front-separator' => 'Front Separator',
'coin-edges-id' => 'Edge ID',
'coin-edges-price' => 'Edge Price',
'coin-back-paneltext1' => 'Back Text 1',
'coin-back-paneltext2' => 'Back Text 2',
'coin-back-top-textcolorname' => 'Back Top Color',
'coin-back-top-textcolorcode' => 'Back Top Color Code',
'coin-back-bottom-textcolorname' => 'Back Bottom Color',
'coin-back-bottom-textcolorcode' => 'Back Bottom Color Code',
'coin-back-basecolorname' => 'Back Base Color',
'coin-back-basecolorcode' => 'Back Base Color Code',
'coin-back-bordercolorname' => 'Back Border Color',
'coin-back-bordercolorcode' => 'Back Border Color Code',
'coin-back-bgcolorname' => 'Back BG Color',
'coin-back-bgcolorcode' => 'Back BG Color Code',
'coin-back-seal-imageid' => 'Back Seal ID',
'coin-back-seal-image' => 'Back Seal Image',
'coin-back-image' => 'Back Coin Image URL',
'coin-back-font' => 'Back Font',
'coin-back-separator' => 'Back Separator',
// owlb_coin_* extended fields (set by our badge designer backend)
'owlb_coin_edge' => 'Edge',
'owlb_coin_edge_price' => 'Edge Price',
'owlb_coin_packaging' => 'Packaging',
'owlb_coin_base_color' => 'Base Color',
'owlb_coin_front_ring' => 'Front Text Ring',
'owlb_coin_front_inner' => 'Front Inner Circle',
'owlb_coin_back_ring' => 'Back Text Ring',
'owlb_coin_back_inner' => 'Back Inner Circle',
'owlb_coin_front_element' => 'Front Element',
'owlb_coin_back_element' => 'Back Element',
];
// Image URL keys — allow both full URLs and base64 data URIs
$image_keys = [
'owlb_preview_image',
'form-collar-image', 'form-collar-image-wm-off',
'form-coin-front-image', 'form-coin-back-image',
'coin-front-image', 'coin-back-image',
];
// Capture from $_GET (HMAC redirect) and $_POST (direct form)
$src = array_merge( $_GET, $_POST, $_REQUEST );
foreach ( $fields as $key => $label ) {
if ( isset( $src[ $key ] ) && strlen( (string) $src[ $key ] ) > 0 ) {
if ( in_array( $key, $image_keys, true ) ) {
$val = $src[ $key ];
// Allow both URLs and base64 data URIs
if ( strpos( $val, 'data:image/' ) === 0 ) {
$cart_item_data[ $key ] = $val;
} else {
$cart_item_data[ $key ] = esc_url_raw( wp_unslash( $val ) );
}
} else {
$cart_item_data[ $key ] = sanitize_text_field( wp_unslash( $src[ $key ] ) );
}
}
}
// Always generate unique key for designer items to prevent unwanted cart merging
$design_id = $cart_item_data['owlb_design_id'] ?? ( $src['owlb_design_id'] ?? '' );
if ( $design_id || ! empty( $cart_item_data['owlb_price'] ) ) {
$cart_item_data['owlb_unique_key'] = md5( microtime() . ( $design_id ?: rand() ) );
}
// Zero out WC_Product_Addons prices for designer items (designer price already includes all add-ons)
if ( ! empty( $cart_item_data['owlb_price'] ) ) {
$unit_price = floatval( $cart_item_data['owlb_price'] );
$cart_item_data['_is_order_again'] = true;
$cart_item_data['_order_again_unit_total'] = $unit_price;
$cart_item_data['_order_again_unit_subtotal'] = $unit_price;
$cart_item_data['addons_price'] = 0;
if ( ! empty( $cart_item_data['addons'] ) && is_array( $cart_item_data['addons'] ) ) {
foreach ( $cart_item_data['addons'] as &$addon ) {
$addon['price'] = 0;
}
}
}
return $cart_item_data;
}, 100, 3 );
// Override Product Add-Ons & Theme price modifications when cart item is created
add_filter( 'woocommerce_add_cart_item', function( $cart_item, $cart_item_key ) {
if ( isset( $cart_item['owlb_price'] ) && strlen( (string) $cart_item['owlb_price'] ) > 0 ) {
$unit_price = floatval( $cart_item['owlb_price'] );
if ( $unit_price >= 0 && isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) ) {
$cart_item['_is_order_again'] = true;
$cart_item['_order_again_unit_total'] = $unit_price;
$cart_item['_order_again_unit_subtotal'] = $unit_price;
$cart_item['data']->owlb_custom_price = $unit_price;
$cart_item['data']->set_price( $unit_price );
$cart_item['data']->set_regular_price( $unit_price );
$cart_item['data']->set_sale_price( '' );
}
}
return $cart_item;
}, 999999, 2 );
// Restore custom designer session properties when cart items are loaded from DB session
add_filter( 'woocommerce_get_cart_item_from_session', function( $cart_item, $values, $key ) {
$price_val = $values['owlb_price'] ?? ( $cart_item['owlb_price'] ?? null );
if ( $price_val !== null && strlen( (string) $price_val ) > 0 ) {
$unit_price = floatval( $price_val );
if ( $unit_price >= 0 ) {
$cart_item['owlb_price'] = $unit_price;
$cart_item['_is_order_again'] = true;
$cart_item['_order_again_unit_total'] = $unit_price;
$cart_item['_order_again_unit_subtotal'] = $unit_price;
if ( isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) ) {
$cart_item['data']->owlb_custom_price = $unit_price;
$cart_item['data']->set_price( $unit_price );
$cart_item['data']->set_regular_price( $unit_price );
$cart_item['data']->set_sale_price( '' );
}
}
}
if ( isset( $values['owlb_design_id'] ) ) {
$cart_item['owlb_design_id'] = $values['owlb_design_id'];
}
return $cart_item;
}, 999999, 3 );
// Unhook theme's unpatched priority 20 and priority 150 price calculators
add_action( 'wp_loaded', function() {
global $wp_filter;
if ( isset( $wp_filter['woocommerce_before_calculate_totals'] ) ) {
unset( $wp_filter['woocommerce_before_calculate_totals']->callbacks[10] );
unset( $wp_filter['woocommerce_before_calculate_totals']->callbacks[20] );
}
remove_action( 'woocommerce_before_calculate_totals', 'custom_calculate_totals', 150 );
}, 999 );
// Re-add safe pricing logic for standard items while preserving designer prices
add_action( 'woocommerce_before_calculate_totals', function( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
static $running = false;
if ( $running ) return;
$running = true;
// 1. Process standard site items with attachment pricing rules (skipping designer items)
$pricing_rules = function_exists( 'get_field' ) ? get_field( 'attachment_pricing', 'option' ) : null;
if ( ! empty( $pricing_rules ) && is_array( $pricing_rules ) ) {
foreach ( $cart_object->get_cart() as $cart_item ) {
if ( ! empty( $cart_item['owlb_price'] ) ) {
continue;
}
$product = $cart_item['data'] ?? null;
if ( ! $product || ! is_object( $product ) ) continue;
$qty = $cart_item['quantity'] ?? 1;
$original_price = floatval( $product->get_price() );
$adjustment = 0;
if ( ! empty( $cart_item['addons'] ) && is_array( $cart_item['addons'] ) ) {
foreach ( $cart_item['addons'] as $addon ) {
$addon_price = floatval( $addon['price'] ?? 0 );
$adjustment -= $addon_price;
foreach ( $pricing_rules as $rule ) {
if (
strtolower( trim( $rule['attachment_name'] ?? '' ) ) === strtolower( trim( $addon['value'] ?? '' ) )
&& $qty >= intval( $rule['min_qty'] ?? 0 )
&& $qty <= intval( $rule['max_qty'] ?? 999999 ) ) { $adjustment +=floatval( $rule['price'] ?? 0 ); break; } } } } if (
function_exists( 'is_product_with_builder' ) && is_product_with_builder( 'patches' , $product->get_id() ) ) {
$product->set_price( $original_price + $adjustment );
}
}
}
if ( ! isset( $GLOBALS['cart_object_rank_number_price_seted'] ) || ! is_array(
$GLOBALS['cart_object_rank_number_price_seted'] ) ) {
$GLOBALS['cart_object_rank_number_price_seted'] = [];
}
foreach ( $cart_object->get_cart() as $hash => $value ) {
// Priority 1: Designer custom price override
$price_val = $value['owlb_price'] ?? ( $value['data']->owlb_custom_price ?? ( $_REQUEST['owlb_price'] ?? (
$_GET['owlb_price'] ?? null ) ) );
if ( $price_val !== null && strlen( (string) $price_val ) > 0 ) {
$unit_price = floatval( $price_val );
if ( $unit_price >= 0 && isset( $value['data'] ) && is_object( $value['data'] ) ) {
$value['data']->owlb_custom_price = $unit_price;
$value['data']->set_price( $unit_price );
$value['data']->set_regular_price( $unit_price );
$value['data']->set_sale_price( '' );
// Mark item in theme's global bypass array so theme.php skips recalculation
if ( ! in_array( $hash, $GLOBALS['cart_object_rank_number_price_seted'], true ) ) {
$GLOBALS['cart_object_rank_number_price_seted'][] = $hash;
}
// Zero out WC_Product_Addons price adjustments on cart contents
if ( isset( $cart_object->cart_contents[ $hash ] ) ) {
$cart_object->cart_contents[ $hash ]['addons_price'] = 0;
if ( ! empty( $cart_object->cart_contents[ $hash ]['addons'] ) && is_array( $cart_object->cart_contents[ $hash
]['addons'] ) ) {
foreach ( $cart_object->cart_contents[ $hash ]['addons'] as &$ad ) {
$ad['price'] = 0;
}
}
}
// Wipe out stored dynamic pricing adjustments for designer items
if ( isset( $cart_object->cart_contents[ $hash ]['discounts'] ) ) {
unset( $cart_object->cart_contents[ $hash ]['discounts'] );
}
if ( isset( $cart_object->cart_contents[ $hash ]['discounts_before_tax'] ) ) {
unset( $cart_object->cart_contents[ $hash ]['discounts_before_tax'] );
}
continue; // Skip theme's patch builder pricing calculations for designer items
}
}
// Priority 2: Standard theme patch builder pricing calculations for standard site items
$product = $value['data'];
if ( ! is_object( $product ) ) continue;
$original_price = floatval( get_field( 'base_price', $product->get_id() ) );
if ( ! $original_price ) {
$original_price = floatval( $product->get_price() );
}
$pricing_rules = get_field( 'attachment_pricing', $product->get_id() );
$adjustment = 0;
$qty = intval( $value['quantity'] ?? 1 );
if ( ! empty( $value['addons'] ) && is_array( $value['addons'] ) && ! empty( $pricing_rules ) && is_array(
$pricing_rules ) ) {
foreach ( $value['addons'] as $addon ) {
foreach ( $pricing_rules as $rule ) {
if (
strtolower( trim( $rule['attachment_name'] ?? '' ) ) === strtolower( trim( $addon['value'] ?? '' ) )
&& $qty >= intval( $rule['min_qty'] ?? 0 )
&& $qty <= intval( $rule['max_qty'] ?? 999999 ) ) { $adjustment +=floatval( $rule['price'] ?? 0 ); break; } } } } if
( function_exists( 'is_product_with_builder' ) && is_product_with_builder( 'patches' , $product->get_id() ) ) {
$product->set_price( $original_price + $adjustment );
}
}
// 2. Call theme's custom_calculate_totals for standard items
if ( function_exists( 'custom_calculate_totals' ) ) {
custom_calculate_totals( $cart_object );
}
$running = false;
}, 1 );
// Disable WooCommerce Dynamic Pricing plugin for designer items (preserves designer unit price)
add_filter( 'woocommerce_dynamic_pricing_process_product_discounts', function( $process, $product = null,
$module_id = '', $module = null, $cart_item = null ) {
if ( is_array( $cart_item ) ) {
if ( ! empty( $cart_item['owlb_price'] ) || ! empty( $cart_item['owlb_design_id'] ) ) {
return false;
}
}
if ( ! empty( $_GET['owlb_price'] ) || ! empty( $_REQUEST['owlb_price'] ) || ! empty( $_GET['owl_add_to_cart'] )
) {
return false;
}
return $process;
}, 999999, 5 );
add_filter( 'woocommerce_dynamic_pricing_is_object_discounted', function( $is_discounted, $cart_item = null,
$cart_item_key = '' ) {
if ( is_array( $cart_item ) ) {
if ( ! empty( $cart_item['owlb_price'] ) || ! empty( $cart_item['owlb_design_id'] ) ) {
return false;
}
}
if ( ! empty( $_GET['owlb_price'] ) || ! empty( $_REQUEST['owlb_price'] ) || ! empty( $_GET['owl_add_to_cart'] )
) {
return false;
}
return $is_discounted;
}, 999999, 3 );
// Helper to resolve designer unit price for a given WC_Product instance
if ( ! function_exists( 'owlb_get_product_unit_price' ) ) {
function owlb_get_product_unit_price( $product ) {
if ( is_object( $product ) && isset( $product->owlb_custom_price ) && $product->owlb_custom_price !== null ) {
return $product->owlb_custom_price;
}
if ( function_exists( 'WC' ) && WC()->cart && ! empty( WC()->cart->get_cart() ) ) {
$product_id = is_object( $product ) && method_exists( $product, 'get_id' ) ? intval( $product->get_id() ) : 0;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$price_val = $cart_item['owlb_price'] ?? null;
if ( $price_val !== null && strlen( (string) $price_val ) > 0 ) {
$item_id = 0;
if ( ! empty( $cart_item['product_id'] ) ) {
$item_id = intval( $cart_item['product_id'] );
} elseif ( isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) && method_exists( $cart_item['data'],
'get_id' ) ) {
$item_id = intval( $cart_item['data']->get_id() );
}
if ( ! $product_id || ! $item_id || $product_id === $item_id ) {
$unit_price = floatval( $price_val );
if ( $unit_price >= 0 ) {
if ( is_object( $product ) ) {
$product->owlb_custom_price = $unit_price;
}
return $unit_price;
}
}
}
}
}
if ( ! function_exists( 'owlb_get_edit_design_url' ) ) {
function owlb_get_edit_design_url( $cart_item, $cart_item_key ) {
$product_id = ! empty( $cart_item['product_id'] )
? intval( $cart_item['product_id'] )
: ( isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) ? intval( $cart_item['data']->get_id() ) : 0
);
$design_id = $cart_item['owlb_design_id'] ?? ( $cart_item['owlb_token'] ?? '' );
if ( ! $design_id || ! $product_id ) {
return '';
}
$user_id = is_user_logged_in() ? get_current_user_id() : 0;
$user_email = is_user_logged_in() ? ( wp_get_current_user()->user_email ) : '';
$user_name = is_user_logged_in() ? ( wp_get_current_user()->display_name ) : '';
$exp = time() + 86400;
$secret = defined('OWL_MEDIA_SECRET') ? OWL_MEDIA_SECRET : 'OwlWP2026!BadgeSave#Secure';
$sig_payload = "{$user_id}|{$user_email}|{$product_id}|{$exp}";
$sig = hash_hmac('sha256', $sig_payload, $secret);
$params = [
'woo_user_id' => $user_id,
'woo_email' => $user_email,
'woo_name' => $user_name,
'woo_product' => $product_id,
'woo_exp' => $exp,
'woo_sig' => $sig,
'owlb_design_id' => $design_id,
'replace_cart_item' => $cart_item_key,
];
return 'https://designer.owlbadges.com/?' . http_build_query($params);
}
}
// Force get_price() to return our custom unit price even if ACF/Dynamic Pricing/PAO filters get_price
add_filter( 'woocommerce_product_get_price', function( $price, $product ) {
$custom_price = owlb_get_product_unit_price( $product );
return $custom_price !== null ? $custom_price : $price;
}, 999999, 2 );
add_filter( 'woocommerce_product_variation_get_price', function( $price, $product ) {
$custom_price = owlb_get_product_unit_price( $product );
return $custom_price !== null ? $custom_price : $price;
}, 999999, 2 );
add_filter( 'woocommerce_product_get_regular_price', function( $price, $product ) {
$custom_price = owlb_get_product_unit_price( $product );
return $custom_price !== null ? $custom_price : $price;
}, 999999, 2 );
add_filter( 'woocommerce_product_get_sale_price', function( $price, $product ) {
$custom_price = owlb_get_product_unit_price( $product );
return $custom_price !== null ? $custom_price : $price;
}, 999999, 2 );
add_filter( 'woocommerce_get_price_html', function( $price_html, $product ) {
$custom_price = owlb_get_product_unit_price( $product );
return $custom_price !== null ? wc_price( $custom_price ) : $price_html;
}, 999999, 2 );
add_filter( 'woocommerce_cart_product_price', function( $price_html, $product ) {
$custom_price = owlb_get_product_unit_price( $product );
return $custom_price !== null ? wc_price( $custom_price ) : $price_html;
}, 999999, 2 );
// Guarantee cart HTML display uses our unit price and subtotal
add_filter( 'woocommerce_cart_item_price', function( $price_html, $cart_item, $cart_item_key ) {
$unit_price = null;
$source = 'none';
if ( isset( $cart_item['owlb_price'] ) && strlen( (string) $cart_item['owlb_price'] ) > 0 ) {
$unit_price = floatval( $cart_item['owlb_price'] );
$source = 'cart_item';
} elseif ( isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) && isset(
$cart_item['data']->owlb_custom_price ) ) {
$unit_price = floatval( $cart_item['data']->owlb_custom_price );
$source = 'product_object';
} elseif ( function_exists( 'WC' ) && WC()->cart ) {
$session_cart = WC()->cart->get_cart();
if ( isset( $session_cart[ $cart_item_key ]['owlb_price'] ) && strlen( (string) $session_cart[ $cart_item_key
]['owlb_price'] ) > 0 ) {
$unit_price = floatval( $session_cart[ $cart_item_key ]['owlb_price'] );
$source = 'session_cart';
} else {
$p_val = owlb_get_product_unit_price( $cart_item['data'] ?? null );
if ( $p_val !== null ) {
$unit_price = $p_val;
$source = 'owlb_get_product_unit_price';
}
}
}
if ( $unit_price !== null && $unit_price >= 0 ) {
return wc_price( $unit_price ) .
'';
}
return $price_html .
'';
}, 999999, 3 );
add_filter( 'woocommerce_cart_item_subtotal', function( $subtotal_html, $cart_item, $cart_item_key ) {
$unit_price = null;
if ( isset( $cart_item['owlb_price'] ) && strlen( (string) $cart_item['owlb_price'] ) > 0 ) {
$unit_price = floatval( $cart_item['owlb_price'] );
} elseif ( isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) && isset(
$cart_item['data']->owlb_custom_price ) ) {
$unit_price = floatval( $cart_item['data']->owlb_custom_price );
} elseif ( function_exists( 'WC' ) && WC()->cart ) {
$session_cart = WC()->cart->get_cart();
if ( isset( $session_cart[ $cart_item_key ]['owlb_price'] ) && strlen( (string) $session_cart[ $cart_item_key
]['owlb_price'] ) > 0 ) {
$unit_price = floatval( $session_cart[ $cart_item_key ]['owlb_price'] );
}
}
if ( $unit_price !== null && $unit_price >= 0 ) {
$qty = ! empty( $cart_item['quantity'] ) ? intval( $cart_item['quantity'] ) : 1;
return wc_price( $unit_price * $qty );
}
return $subtotal_html;
}, 999999, 3 );
// ── 2. Replace cart thumbnail with designer preview image ─────────────────────
add_filter( 'woocommerce_cart_item_thumbnail', function( $thumbnail, $cart_item, $cart_item_key ) {
// Priority: owlb_preview_image (URL) → form-collar-image
// NOTE: form-coin-front-image is intentionally skipped — our designer sends
// the composite (front+back) as owlb_preview_image; using form-coin-front-image
// too would cause the website's own plugin to show 4 coins instead of 2.
$preview = '';
if ( ! empty( $cart_item['owlb_preview_image'] ) ) {
$preview = $cart_item['owlb_preview_image'];
} elseif ( ! empty( $cart_item['form-collar-image'] ) ) {
$preview = $cart_item['form-collar-image'];
}
if ( ! $preview ) {
return $thumbnail;
}
if ( strpos( $preview, 'data:image/' ) === 0 ) {
$src = esc_attr( $preview );
} else {
$src = esc_url( $preview );
}
return ' ';
}, 99, 3 );
// ── 3. Display design details in cart & checkout ──────────────────────────────
add_filter( 'woocommerce_get_item_data', function( $data, $cart_item ) {
// Preview image (URL only — skip base64)
$preview_img = ! empty( $cart_item['owlb_preview_image'] ) ? $cart_item['owlb_preview_image'] : '';
if ( ! $preview_img && ! empty( $cart_item['form-coin-front-image'] ) ) {
$preview_img = $cart_item['form-coin-front-image'];
}
if ( ! $preview_img && ! empty( $cart_item['form-collar-image'] ) ) {
$preview_img = $cart_item['form-collar-image'];
}
if ( $preview_img && strpos( $preview_img, 'data:image/' ) !== 0 ) {
$img_url = esc_url( $preview_img );
$data[] = [
'name' => 'Badge Preview',
'value' => $img_url,
'display' => ' ',
];
}
// Detect product type from cart data
$is_coin = ! empty( $cart_item['form-coin-front-paneltext1'] )
|| ! empty( $cart_item['coin-front-paneltext1'] )
|| ! empty( $cart_item['owlb_coin_edge'] );
$is_collar = ! $is_coin && (
! empty( $cart_item['form-collar-text'] )
|| ! empty( $cart_item['collarPinTextPanel'] )
);
if ( $is_coin ) {
// ── Challenge Coin display ─────────────────────────────────────────
// Helper: read first non-empty value from a list of keys
$get = function( array $keys ) use ( $cart_item ) {
foreach ( $keys as $k ) {
if ( ! empty( $cart_item[ $k ] ) ) {
return $cart_item[ $k ];
}
}
return '';
};
$rows = [
[ 'Front Text Panel 1', [ 'form-coin-front-paneltext1', 'coin-front-paneltext1' ] ],
[ 'Front Text Color', [ 'form-coin-front-panel1-color-name', 'coin-front-top-textcolorname' ] ],
[ 'Front Text Font', [ 'form-coin-front-font', 'coin-front-font' ] ],
[ 'Front Text Panel 2', [ 'form-coin-front-paneltext2', 'coin-front-paneltext2' ] ],
[ 'Front Text 2 Color', [ 'form-coin-front-panel2-color-name', 'coin-front-bottom-textcolorname' ] ],
[ 'Back Text Panel 1', [ 'form-coin-back-paneltext1', 'coin-back-paneltext1' ] ],
[ 'Back Text Color', [ 'form-coin-back-panel1-color-name', 'coin-back-top-textcolorname' ] ],
[ 'Back Text Font', [ 'form-coin-back-font', 'coin-back-font' ] ],
[ 'Back Text Panel 2', [ 'form-coin-back-paneltext2', 'coin-back-paneltext2' ] ],
[ 'Back Text 2 Color', [ 'form-coin-back-panel2-color-name', 'coin-back-bottom-textcolorname' ] ],
[ 'Base Color', [ 'owlb_coin_base_color', 'form-coin-front-basecolor-name', 'coin-front-basecolorname' ] ],
[ 'Edge', [ 'owlb_coin_edge' ] ],
[ 'Front Text Ring', [ 'owlb_coin_front_ring' ] ],
[ 'Front Inner Circle', [ 'owlb_coin_front_inner' ] ],
[ 'Front Element', [ 'owlb_coin_front_element' ] ],
[ 'Back Text Ring', [ 'owlb_coin_back_ring' ] ],
[ 'Back Inner Circle', [ 'owlb_coin_back_inner' ] ],
[ 'Back Element', [ 'owlb_coin_back_element' ] ],
[ 'Packaging', [ 'owlb_coin_packaging' ] ],
];
foreach ( $rows as [$label, $keys] ) {
$val = $get( $keys );
if ( $val !== '' ) {
$data[] = [
'name' => $label,
'value' => esc_html( $val ),
'display' => esc_html( $val ),
];
}
}
if ( ! empty( $cart_item['owlb_design_id'] ) ) {
$data[] = [
'name' => 'Design #',
'value' => esc_html( $cart_item['owlb_design_id'] ),
'display' => esc_html( $cart_item['owlb_design_id'] ),
];
}
} elseif ( $is_collar ) {
// ── Collar-pin display ─────────────────────────────────────────────
$cp_display = [
'form-collar-text' => 'Pin Text',
'form-collar-text-color-name' => 'Pin Text Color',
'form-collar-text-style' => 'Pin Text Style',
'form-collar-attachment' => 'Attachment',
];
$cp_fallbacks = [
'form-collar-text' => 'collarPinTextPanel',
'form-collar-text-color-name' => 'collarPinTextColorName',
'form-collar-text-style' => 'collarPinTextStyle',
'form-collar-attachment' => 'collarPinAttachment',
];
foreach ( $cp_display as $key => $label ) {
$val = ! empty( $cart_item[ $key ] )
? $cart_item[ $key ]
: ( ! empty( $cart_item[ $cp_fallbacks[ $key ] ] ) ? $cart_item[ $cp_fallbacks[ $key ] ] : '' );
if ( $val ) {
$data[] = [
'name' => $label,
'value' => esc_html( $val ),
'display' => esc_html( $val ),
];
}
}
if ( ! empty( $cart_item['owlb_design_id'] ) ) {
$data[] = [
'name' => 'Design #',
'value' => esc_html( $cart_item['owlb_design_id'] ),
'display' => esc_html( $cart_item['owlb_design_id'] ),
];
}
} else {
// ── Standard badge / patch display ────────────────────────────────
$display = [
'owlb_type' => 'Badge Type',
'owlb_size' => 'Size',
'owlb_color' => 'Color',
'owlb_colors' => 'Patch Colors',
'owlb_font' => 'Font',
'owlb_text_1' => 'Line 1',
'owlb_text_2' => 'Line 2',
'owlb_text_3' => 'Line 3',
'owlb_text_4' => 'Line 4',
'owlb_seal' => 'Seal',
'owlb_attachment' => 'Attachment',
'owlb_design_id' => 'Design #',
];
foreach ( $display as $key => $label ) {
if ( ! empty( $cart_item[ $key ] ) ) {
$data[] = [
'name' => $label,
'value' => esc_html( $cart_item[ $key ] ),
'display' => esc_html( $cart_item[ $key ] ),
];
}
}
}
return $data;
}, 10, 2 );
// ── 4. Save design details to order line item (visible in admin orders) ────────
add_action( 'woocommerce_checkout_create_order_line_item', function( $item, $cart_item_key, $values, $order ) {
$meta_fields = [
'owlb_design_id' => 'Design ID',
'owlb_template' => 'Template',
'owlb_type' => 'Badge Type',
'owlb_size' => 'Size',
'owlb_color' => 'Color',
'owlb_colors' => 'Patch Colors',
'owlb_font' => 'Font',
'owlb_text_1' => 'Line 1',
'owlb_text_type_1' => 'Line 1 Type',
'owlb_text_2' => 'Line 2',
'owlb_text_type_2' => 'Line 2 Type',
'owlb_text_3' => 'Line 3',
'owlb_text_type_3' => 'Line 3 Type',
'owlb_text_4' => 'Line 4',
'owlb_text_type_4' => 'Line 4 Type',
'owlb_seal' => 'Seal',
'owlb_attachment' => 'Attachment',
'owlb_price' => 'Design Price',
'owlb_preview_image' => 'Badge Preview URL',
// Collar-pin specific
'form-collar-text' => 'Pin Text',
'form-collar-text-color-name' => 'Pin Text Color',
'form-collar-text-style' => 'Pin Text Style',
'form-collar-attachment' => 'Collar Attachment',
'collarPinTextPanel' => 'Pin Text (alt)',
'collarPinTextColorName' => 'Pin Text Color (alt)',
'collarPinTextStyle' => 'Pin Text Style (alt)',
'collarPinAttachment' => 'Collar Attachment (alt)',
// Challenge-coin specific
'form-coin-front-paneltext1' => 'Front Text Panel 1',
'form-coin-front-paneltext2' => 'Front Text Panel 2',
'form-coin-back-paneltext1' => 'Back Text Panel 1',
'form-coin-back-paneltext2' => 'Back Text Panel 2',
'form-coin-front-panel1-color-name' => 'Front Text Color',
'form-coin-front-panel2-color-name' => 'Front Text 2 Color',
'form-coin-back-panel1-color-name' => 'Back Text Color',
'form-coin-back-panel2-color-name' => 'Back Text 2 Color',
'form-coin-front-basecolor-name' => 'Front Base Color',
'form-coin-back-basecolor-name' => 'Back Base Color',
'form-coin-front-font' => 'Front Text Font',
'form-coin-back-font' => 'Back Text Font',
'form-coin-edges-price' => 'Coin Edge Price',
'owlb_coin_edge' => 'Edge',
'owlb_coin_packaging' => 'Packaging',
'owlb_coin_base_color' => 'Base Color',
'owlb_coin_front_ring' => 'Front Text Ring',
'owlb_coin_front_inner' => 'Front Inner Circle',
'owlb_coin_back_ring' => 'Back Text Ring',
'owlb_coin_back_inner' => 'Back Inner Circle',
'owlb_coin_front_element' => 'Front Element',
'owlb_coin_back_element' => 'Back Element',
];
foreach ( $meta_fields as $key => $label ) {
if ( ! empty( $values[ $key ] ) && strpos( $values[ $key ], 'data:image/' ) !== 0 ) {
$item->add_meta_data( $label, $values[ $key ], true );
}
}
}, 10, 4 );
// ── 5. Restore our custom keys from WooCommerce session ───────────────────────
// Another plugin (owl-badge-media-urls.php) may rebuild cart items from session
// and only restore the keys it knows about, silently dropping ours.
// This filter explicitly re-applies every key we stored so nothing is lost.
add_filter( 'woocommerce_get_cart_item_from_session', function( $cart_item, $values, $key ) {
$our_keys = [
// Standard owlb
'owlb_design_id', 'owlb_token', 'owlb_template', 'owlb_type', 'owlb_size',
'owlb_color', 'owlb_font', 'owlb_text_1', 'owlb_text_2', 'owlb_text_3', 'owlb_text_4',
'owlb_seal', 'owlb_attachment', 'owlb_colors', 'owlb_price', 'owlb_qty',
'owlb_preview_image', 'owlb_pin_text', 'owlb_pin_text_color', 'owlb_pin_text_style',
// Collar-pin
'form-collar-text', 'form-collar-text-color', 'form-collar-text-color-name',
'form-collar-text-style', 'form-collar-text-size-label',
'form-collar-attachment',
'form-collar-image', 'form-collar-image-wm-off',
'collarPinTextPanel', 'collarPinTextColor', 'collarPinTextColorName',
'collarPinTextStyle', 'collarPinTextSizeLabel', 'collarPinAttachment',
// Challenge coin — form-coin-* primary keys
'form-coin-front-paneltext1', 'form-coin-front-paneltext2',
'form-coin-back-paneltext1', 'form-coin-back-paneltext2',
'form-coin-front-panel1-color-name', 'form-coin-front-panel1-color-code',
'form-coin-front-panel2-color-name', 'form-coin-front-panel2-color-code',
'form-coin-back-panel1-color-name', 'form-coin-back-panel1-color-code',
'form-coin-back-panel2-color-name', 'form-coin-back-panel2-color-code',
'form-coin-front-basecolor-name', 'form-coin-front-basecolor-code',
'form-coin-back-basecolor-name', 'form-coin-back-basecolor-code',
'form-coin-front-bordercolor-name', 'form-coin-front-bordercolor-code',
'form-coin-back-bordercolor-name', 'form-coin-back-bordercolor-code',
'form-coin-front-bgcolor-name', 'form-coin-front-bgcolor-code',
'form-coin-back-bgcolor-name', 'form-coin-back-bgcolor-code',
'form-coin-front-seal-id', 'form-coin-back-seal-id',
'form-coin-front-seal-image', 'form-coin-back-seal-image',
'form-coin-front-image', 'form-coin-back-image',
'form-coin-edges-id', 'form-coin-edges-price',
'form-coin-front-font', 'form-coin-back-font',
// Challenge coin — coin-* aliases
'coin-front-paneltext1', 'coin-front-paneltext2',
'coin-back-paneltext1', 'coin-back-paneltext2',
'coin-front-top-textcolorname', 'coin-front-top-textcolorcode',
'coin-front-bottom-textcolorname', 'coin-front-bottom-textcolorcode',
'coin-back-top-textcolorname', 'coin-back-top-textcolorcode',
'coin-back-bottom-textcolorname', 'coin-back-bottom-textcolorcode',
'coin-front-basecolorname', 'coin-front-basecolorcode',
'coin-back-basecolorname', 'coin-back-basecolorcode',
'coin-front-bordercolorname', 'coin-front-bordercolorcode',
'coin-back-bordercolorname', 'coin-back-bordercolorcode',
'coin-front-bgcolorname', 'coin-front-bgcolorcode',
'coin-back-bgcolorname', 'coin-back-bgcolorcode',
'coin-front-seal-imageid', 'coin-front-seal-image',
'coin-back-seal-imageid', 'coin-back-seal-image',
'coin-front-image', 'coin-back-image',
'coin-edges-id', 'coin-edges-price',
'coin-front-font', 'coin-front-separator',
'coin-back-font', 'coin-back-separator',
// Challenge coin — owlb_coin_* extended fields
'owlb_coin_edge', 'owlb_coin_edge_price', 'owlb_coin_packaging',
'owlb_coin_base_color',
'owlb_coin_front_ring', 'owlb_coin_front_inner', 'owlb_coin_front_element',
'owlb_coin_back_ring', 'owlb_coin_back_inner', 'owlb_coin_back_element',
'owlb_unique_key',
];
foreach ( $our_keys as $k ) {
if ( isset( $values[ $k ] ) && ! isset( $cart_item[ $k ] ) ) {
$cart_item[ $k ] = $values[ $k ];
}
}
if ( isset( $values['owlb_price'] ) && strlen( (string) $values['owlb_price'] ) > 0 ) {
$unit_price = floatval( $values['owlb_price'] );
if ( $unit_price >= 0 ) {
$cart_item['owlb_price'] = $unit_price;
if ( isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) ) {
$cart_item['data']->owlb_custom_price = $unit_price;
$cart_item['data']->set_price( $unit_price );
}
}
}
return $cart_item;
}, 20, 3 );
// ── 6. Show design meta cleanly in admin order detail page ────────────────────
add_filter( 'woocommerce_order_item_display_meta_key', function( $key ) {
// Already using human-readable labels above — return as-is
return $key;
} );
California Highway Patrol Badge 16-H30CA | Owl Badges
California Highway Patrol Badge 16-H30CA
Style
16-H30CA · 7 point star
$ 150.00
per badge · free
mold and setup
Design now
Get a quote
At a glance
Shape 7 Point Star Text panels 3 Seal or logo well Centered, 41% of face Material Die-struck alloy brass Dimensions 2.25″ × 3.13″, .25 lb Mold and setup Free
What each panel holds
Panel 1
Up to 40 characters
Panel 2
Up to 40 characters
Panel 3
Up to 24 characters
Sizes and order minimums
Size
Minimum
3" x 2.91" Premium
1 piece
1.25" x 1.21" Lapel Pin
50 pieces
Designing and ordering custom badges has never been easier. No design skill required, design a professional badge, get an instant quote and place your order in just minutes.
Follow these simple step by step video tutorials to design a perfect custom badge and seal with your organization logo and tag line. Scroll down and select the step you need help with!
Theme overlays are a perfect way to help your organization stand out. Select from a variety of graphics to create a design that is unique and exciting. Theme Overlays will help your organization look professional and something your staff will want to show off and be proud of.
Big & Mid Badges Minimum order: 20 badges per theme, add +$10 per badge
Mini Badges Minimum order: 50 badges per theme, add +$2 per badge
Patches Minimum order: 10 patches per theme, add +FREE
Name Tags Minimum order: 1 name tag per theme, add +$2 per name tag
Air Fresheners Minimum order: 50 air freshener badges per theme, FREE no cost to add themes to air fresheners
Follow these simple step by step video tutorials to design a perfect badge with a theme overlay. Scroll down and select the step you need help with!