post_type) { $ids[] = (int) $p->ID; } } if (count($ids) < 2) { return $posts; } $audience = class_exists('AIEO_Identity_Bridge') ? AIEO_Identity_Bridge::audience_key_for_current_user() : 'guest'; if (class_exists('AIEO_Effective_Prices') && method_exists('AIEO_Effective_Prices', 'prime')) { AIEO_Effective_Prices::prime($ids, self::price_audience($audience)); } if (class_exists('AIEO_Effective_Eligibility') && method_exists('AIEO_Effective_Eligibility', 'prime')) { AIEO_Effective_Eligibility::prime(AIEO_Effective_Eligibility::SURFACE_BRAND_GIFT, $audience, $ids); } return $posts; } public static function is_enabled() { return (bool) get_option(self::FLAG_OPTION, 0); } public static function enqueue_styles() { if (is_admin()) { return; } $wants = function_exists('is_woocommerce') && is_woocommerce(); if (!$wants) { $post = get_post(); $wants = $post instanceof WP_Post && (has_block('woocommerce/product-collection', $post) || has_block('woocommerce/products', $post) || has_block('woocommerce/product-template', $post) || has_block('aieo/recos', $post) || has_block('aieo/product-slider', $post) || (class_exists('\Rooster\Blocks\Elementor\Factory') && \Rooster\Blocks\Elementor\Factory::post_has($post, array('aieo/product-slider')))); } if ($wants) { self::load_styles(); } } public static function load_styles() { if (self::$styles_loaded) { return; } self::$styles_loaded = true; if (self::is_enabled()) { $rel = 'assets/css/aieo-badge-system.css'; $abs = dirname(AIEO_FILE) . '/' . $rel; $ver = file_exists($abs) ? filemtime($abs) : (defined('AIEO_VERSION') ? AIEO_VERSION : '1.0'); wp_enqueue_style('aieo-badge-system', plugins_url($rel, AIEO_FILE), array(), $ver); } if (self::is_enabled() && class_exists('AIEO_DMM_Badges')) { $settings = AIEO_DMM_Badges::get_settings(); if (!empty($settings['hide_wc_onsale'])) { $css = '.woocommerce span.onsale,' . '.woocommerce .onsale,' . 'ul.products li.product .onsale,' . '.products .product .onsale,' . '.wc-block-grid__product-onsale,' . '.wc-block-grid__product .onsale,' . '.wp-block-woocommerce-product-sale-badge,' . '.wc-block-product-template .onsale,' . '.wp-block-woocommerce-product-template .onsale,' . '.om-ppe-product-labels,' . '.om-ppe-label' . '{display:none !important;}'; wp_add_inline_style('aieo-badge-system', $css); } } } private static function price_audience($audience) { static $known = null; if ('guest' === $audience || !class_exists('AIEO_Identity_Bridge')) { return $audience; } if (null === $known) { $known = AIEO_Identity_Bridge::known_audience_keys(); } return in_array($audience, $known, true) ? $audience : 'guest'; } public static function resolve_for_product($product, $surface = 'archive', $audience = null) { if (!class_exists('AIEO_DMM_Badges')) { return array(); } $settings = AIEO_DMM_Badges::get_settings(); $product_id = is_object($product) && method_exists($product, 'get_id') ? (int) $product->get_id() : (int) $product; if ($product_id <= 0) { return array(); } if ($audience === null) { $audience = class_exists('AIEO_Identity_Bridge') ? AIEO_Identity_Bridge::audience_key_for_current_user() : 'guest'; } $price_row = class_exists('AIEO_Effective_Prices') ? AIEO_Effective_Prices::get_for($product_id, self::price_audience($audience)) : null; $out = array(); if (self::family_visible('sale', $surface, $settings)) { $on_sale = self::runtime_is_on_sale($product_id); if ($on_sale) { $out[] = self::dto('sale', $settings, array( 'discount_pct' => is_array($price_row) ? ($price_row['sale_discount_pct'] ?? null) : null, )); } } if (self::family_visible('monthly_offer', $surface, $settings)) { $mo = is_array($price_row) ? !empty($price_row['monthly_offer_active']) : (class_exists('AIEO_DMM_Brand_Discounts') && AIEO_DMM_Brand_Discounts::is_monthly_offer_active($product_id)); if ($mo) { $out[] = self::dto('monthly_offer', $settings); } } if (self::family_visible('pro', $surface, $settings)) { $role_applied = is_array($price_row) && !empty($price_row['role_price_applied']); if ($role_applied) { $out[] = self::dto('pro', $settings); } } if (self::family_visible('new', $surface, $settings)) { $is_new = class_exists('AIEO_DMM_Brand_Discounts') && AIEO_DMM_Brand_Discounts::is_new_product($product_id); if ($is_new) { $out[] = self::dto('new', $settings); } } if (self::family_visible('gift', $surface, $settings)) { $gift_row = class_exists('AIEO_Effective_Eligibility') ? AIEO_Effective_Eligibility::get_for(AIEO_Effective_Eligibility::SURFACE_BRAND_GIFT, $audience, $product_id) : null; if (!is_array($gift_row) && class_exists('AIEO_DMM_Brand_Gifts')) { $rt = AIEO_DMM_Brand_Gifts::is_eligible_for($product_id, $audience); if (!empty($rt['eligible'])) { $gift_row = array( 'eligible' => 1, 'offer_id' => $rt['offer_id'] ?? null, 'payload' => $rt['payload'] ?? array(), ); } } if (is_array($gift_row) && !empty($gift_row['eligible'])) { $out[] = self::dto('gift', $settings, array( 'offer_label' => isset($gift_row['payload']['label']) ? (string) $gift_row['payload']['label'] : '', )); } } usort($out, function($a, $b) { return (int) $a['order'] - (int) $b['order']; }); return $out; } private static function family_visible($key, $surface, array $settings) { $f = isset($settings['families'][$key]) ? $settings['families'][$key] : null; if (!$f || empty($f['enabled'])) { return false; } return !empty($f['surfaces'][$surface]); } private static function dto($key, array $settings, array $extra = array()) { $f = $settings['families'][$key]; $label = (string) $f['label']; if ($key === 'sale' && !empty($extra['discount_pct'])) { if (strpos($label, '{sale}') !== false) { $label = str_replace('{sale}', round((float) $extra['discount_pct']) . '%', $label); } } if ($key === 'gift' && !empty($extra['offer_label'])) { $label = (string) $extra['offer_label']; } return array( 'family' => $key, 'label' => $label, 'icon' => isset($f['icon']) ? (string) $f['icon'] : '', 'icon_image_url' => isset($f['icon_image_url']) ? (string) $f['icon_image_url'] : '', 'tooltip' => isset($f['tooltip']) ? (string) $f['tooltip'] : '', 'bg' => self::colour($key, 0, (string) $f['bg']), 'fg' => self::colour($key, 1, (string) $f['fg']), 'order' => (int) $f['order'], ); } private static function colour($key, $which, $own) { static $roles = array( 'sale' => array('accent-2', 'bg'), 'gift' => array('success', 'bg'), 'pro' => array('contrast', 'bg'), 'new' => array('contrast', 'bg'), 'monthly_offer' => array('accent', 'on-accent'), ); if (!isset($roles[$key]) || !class_exists('AIEO_Theme_Contracts') || 'theme' !== AIEO_Theme_Contracts::design_authority()) { return $own; } return 'var(--wp--preset--color--' . $roles[$key][$which] . ',' . $own . ')'; } public static function render_for_product($product, $surface) { $badges = self::resolve_for_product($product, $surface); if (empty($badges)) { return ''; } $stack_style = ''; if (class_exists('AIEO_DMM_Badges')) { $settings = AIEO_DMM_Badges::get_settings(); $sz = isset($settings['sizes'][$surface]) ? $settings['sizes'][$surface] : array(); $d = is_array($sz) && isset($sz['desktop']) ? (int) $sz['desktop'] : 0; $m = is_array($sz) && isset($sz['mobile']) ? (int) $sz['mobile'] : 0; $vars = array(); if ($d > 0) { $vars[] = '--aieo-badge-fs-d:' . $d . 'px'; } if ($m > 0) { $vars[] = '--aieo-badge-fs-m:' . $m . 'px'; } if (!empty($vars)) { $stack_style = ' style="' . implode(';', $vars) . ';"'; } } $stack = '
'; foreach ($badges as $b) { $style = sprintf( '--aieo-badge-bg:%s;--aieo-badge-fg:%s;order:%d;', esc_attr($b['bg']), esc_attr($b['fg']), (int) $b['order'] ); $cls = 'aieo-badge aieo-badge--' . sanitize_html_class($b['family']); $title_attr = $b['tooltip'] !== '' ? ' title="' . esc_attr($b['tooltip']) . '"' : ''; $img_url = isset($b['icon_image_url']) ? (string) $b['icon_image_url'] : ''; if ($img_url !== '') { $alt = $b['label'] !== '' ? $b['label'] : $b['family']; $stack .= '' . '' . esc_attr($alt) . '' . ''; } else { $icon_name = AIEO_Icons::name_of($b['icon']); if ($b['icon'] === '') { $icon = ''; } elseif ('' !== $icon_name) { $icon = ''; } else { $icon = '' . esc_html($b['icon']) . ''; } $stack .= '' . $icon . '' . esc_html($b['label']) . '' . ''; } } $stack .= '
'; return $stack; } public static function render_archive() { global $product; if (!$product) { return; } if (isset(self::$block_cards[(int) $product->get_id()])) { return; } $html = self::render_for_product($product, 'archive'); if ($html === '') { return; } echo $html; } public static function inject_block_card($block_content, $block, $instance = null) { if (strpos($block_content, 'data-is-descendent-of-query-loop="true"') === false) { return $block_content; } $pid = ($instance instanceof WP_Block && !empty($instance->context['postId'])) ? (int) $instance->context['postId'] : 0; if ($pid <= 0 || 'product' !== get_post_type($pid)) { return $block_content; } self::$block_cards[$pid] = true; $stack = self::render_for_product($pid, 'archive'); if ($stack === '') { return $block_content; } self::load_styles(); return preg_replace('/^(\s*]*\bwp-block-woocommerce-product-image\b[^>]*>)/', '$1' . $stack, $block_content, 1); } public static function inject_pdp_gallery($block_content, $block) { if (!is_singular('product')) { return $block_content; } global $product; if (!$product) { return $block_content; } $stack = self::render_for_product($product, 'pdp'); if ($stack === '') { return $block_content; } return preg_replace( '/(]*wp-block-woocommerce-product-(?:image-)?gallery[^>]*>)/', '$1' . $stack, $block_content, 1 ); } public static function dto_for_product($product, $surface) { $badges = self::resolve_for_product($product, $surface); $compact = array(); foreach ($badges as $b) { $compact[] = array( 'f' => $b['family'], 'l' => $b['label'], 'i' => $b['icon'], 'm' => isset($b['icon_image_url']) ? (string) $b['icon_image_url'] : '', 'b' => $b['bg'], 'g' => $b['fg'], 'o' => $b['order'], ); } return $compact; } private static function runtime_is_on_sale($product_id) { $live_below_regular = static function ($pid) { $reg = get_post_meta((int) $pid, '_regular_price', true); $live = get_post_meta((int) $pid, '_price', true); if ($reg === '' || $live === '') { return false; } $reg = (float) str_replace(',', '.', (string) $reg); $live = (float) str_replace(',', '.', (string) $live); return ($live > 0 && $live < $reg); }; if ($live_below_regular($product_id)) { return true; } $p = function_exists('wc_get_product') ? wc_get_product($product_id) : null; if ($p && method_exists($p, 'is_type') && $p->is_type('variable')) { $children = array_map('intval', (array) $p->get_children()); if ($children && function_exists('update_meta_cache')) { update_meta_cache('post', $children); } foreach ($children as $vid) { if ($live_below_regular($vid)) { return true; } } } return false; } }