is_woocommerce_active()) { add_action('admin_notices', array($this, 'woocommerce_missing_notice')); return; } // Initialize parent menu AboveWP_Admin_Menu::init(); // Add admin settings add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_init', array($this, 'register_settings')); // Remove WordPress admin notices on our admin pages add_action('admin_head', array($this, 'remove_admin_notices_on_plugin_pages')); // Enqueue admin styles add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles')); // Add plugin card to AboveWP dashboard add_action('abovewp_admin_dashboard_plugins', array($this, 'display_plugin_card')); // Add AJAX handler for adding to cart add_action('wp_ajax_abovewp_add_upsell_to_cart', array($this, 'add_upsell_to_cart')); add_action('wp_ajax_nopriv_abovewp_add_upsell_to_cart', array($this, 'add_upsell_to_cart')); // Add AJAX handler for getting upsell data add_action('wp_ajax_abovewp_get_upsell_data', array($this, 'ajax_get_upsell_data')); add_action('wp_ajax_nopriv_abovewp_get_upsell_data', array($this, 'ajax_get_upsell_data')); // Add AJAX handler for admin product search (settings page) add_action('wp_ajax_abovewp_atc_search_products', array($this, 'ajax_search_products')); // Initialize frontend functionality $this->init_frontend(); // Add plugin action links add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'plugin_action_links')); } /** * Check if WooCommerce is active * * @return bool */ private function is_woocommerce_active() { return in_array('woocommerce/woocommerce.php', (array) get_option('active_plugins', array()), true); } /** * Show admin notice if WooCommerce is not active */ public function woocommerce_missing_notice() { ?>

' . __('Settings', 'abovewp-atc-popup-upsell') . ''; array_unshift($links, $settings_link); return $links; } /** * Initialize frontend functionality */ private function init_frontend() { // Only proceed if enabled if (get_option('abovewp_atc_enabled', 'yes') !== 'yes') { return; } // Enqueue frontend scripts and styles add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts')); // Add popup HTML to footer add_action('wp_footer', array($this, 'add_popup_html')); // Add hooks that will work with AJAX add to cart // For single product pages - prepare the upsell data add_action('woocommerce_before_single_product', array($this, 'add_product_upsell_data')); // For shop/category pages - handle AJAX add to cart add_filter('woocommerce_loop_add_to_cart_args', array($this, 'add_data_to_add_to_cart_button'), 10, 2); // Hook into WooCommerce add to cart action for better detection add_action('woocommerce_add_to_cart', array($this, 'on_product_added_to_cart'), 10, 6); // Add cart monitoring script add_action('wp_footer', array($this, 'add_cart_monitoring_script'), 5); // Debug info in footer - disabled in production // if (defined('WP_DEBUG') && WP_DEBUG) { // add_action('wp_footer', array($this, 'debug_info'), 999); // } } /** * Enqueue admin styles */ public function enqueue_admin_styles($hook) { if (strpos($hook, 'abovewp') !== false) { wp_enqueue_style( 'abovewp-font-inter', 'https://fonts.bunny.net/css?family=inter:400,500,600,700', array(), ABOVEWP_ATC_VERSION ); wp_enqueue_style( 'abovewp-admin-default', ABOVEWP_ATC_PLUGIN_URL . 'assets/css/admin-page-default.css', array('abovewp-font-inter'), ABOVEWP_ATC_VERSION ); } // Enqueue Select2 (selectWoo) on our settings page only if ($hook === 'abovewp_page_abovewp-atc-popup-upsell') { wp_enqueue_style('select2', WC()->plugin_url() . '/assets/css/select2.css', array(), WC_VERSION); wp_enqueue_script('selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full.min.js', array('jquery'), WC_VERSION, true); $inline_js = " jQuery(function($) { $('#abovewp_atc_global_products').selectWoo({ ajax: { url: ajaxurl, dataType: 'json', delay: 300, data: function(params) { return { term: params.term, action: 'abovewp_atc_search_products', nonce: '" . esc_js(wp_create_nonce('abovewp_atc_search_products')) . "' }; }, processResults: function(data) { return data; }, cache: true }, minimumInputLength: 2, placeholder: '" . esc_js(__('Search for products...', 'abovewp-atc-popup-upsell')) . "', allowClear: true, templateResult: function(item) { if (item.loading) return item.text; var img = item.image ? '' : ''; return $('' + img + '' + item.text + ' — ' + item.price_html + ''); }, templateSelection: function(item) { return item.text; } }); }); "; wp_add_inline_script('selectWoo', $inline_js); } } /** * Enqueue scripts and styles for the frontend */ public function enqueue_scripts() { // Enhanced page detection - include more pages where add-to-cart might happen $should_load = false; // Standard WooCommerce pages if (is_product() || is_cart() || is_shop() || is_product_category() || is_product_tag()) { $should_load = true; } // Check for WooCommerce-related content on any page if (!$should_load && (is_page() || is_single() || is_home() || is_front_page())) { // Check for WooCommerce shortcodes or blocks global $post; if ($post && ( has_shortcode($post->post_content, 'product') || has_shortcode($post->post_content, 'products') || has_shortcode($post->post_content, 'recent_products') || has_shortcode($post->post_content, 'featured_products') || has_shortcode($post->post_content, 'sale_products') || has_shortcode($post->post_content, 'best_selling_products') || has_shortcode($post->post_content, 'top_rated_products') || strpos($post->post_content, 'wp:woocommerce/') !== false || strpos($post->post_content, 'add-to-cart') !== false )) { $should_load = true; } } // Check if we're on a page that might have Elementor or other page builder WooCommerce widgets if (!$should_load && function_exists('wc_get_page_id')) { // Also load on pages that might have WooCommerce widgets or custom implementations $should_load = true; // For maximum compatibility } if (!$should_load) { return; } wp_enqueue_style( 'abovewp-atc-popup', ABOVEWP_ATC_PLUGIN_URL . 'assets/css/popup.css', array(), ABOVEWP_ATC_VERSION ); wp_enqueue_script( 'abovewp-atc-popup', ABOVEWP_ATC_PLUGIN_URL . 'assets/js/popup.js', array('jquery'), ABOVEWP_ATC_VERSION, true ); // Get custom text settings $success_message_format = get_option('abovewp_atc_success_message_format', '{product_name} ' . __('added to cart!', 'abovewp-atc-popup-upsell')); $add_to_cart_text = get_option('abovewp_atc_add_to_cart_text', __('Add to Cart', 'abovewp-atc-popup-upsell')); $view_cart_text = get_option('abovewp_atc_view_cart_text', __('View Cart', 'abovewp-atc-popup-upsell')); $checkout_text = get_option('abovewp_atc_checkout_text', __('Checkout', 'abovewp-atc-popup-upsell')); $continue_shopping_text = get_option('abovewp_atc_continue_shopping_text', __('Continue Shopping', 'abovewp-atc-popup-upsell')); $popup_title = get_option('abovewp_atc_popup_title', __('You might also like...', 'abovewp-atc-popup-upsell')); $added_to_cart_text = get_option('abovewp_atc_added_to_cart_text', __('Added to cart!', 'abovewp-atc-popup-upsell')); // Prepare enhanced JavaScript parameters $params = array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('abovewp-atc-upsell'), 'wc_ajax_url' => WC_AJAX::get_endpoint('%%endpoint%%'), 'cart_url' => wc_get_cart_url(), 'checkout_url' => wc_get_checkout_url(), 'is_product_page' => is_product(), 'is_shop_page' => is_shop(), 'is_cart_page' => is_cart(), 'current_product_id' => is_product() ? get_the_ID() : 0, 'i18n' => array( 'added_to_cart' => $added_to_cart_text, 'failed_to_add' => __('Failed to add product to cart.', 'abovewp-atc-popup-upsell'), 'view_cart' => $view_cart_text, 'checkout' => $checkout_text, 'continue_shopping' => $continue_shopping_text, 'add_to_cart' => $add_to_cart_text, 'popup_title' => $popup_title, 'success_message_format' => $success_message_format, ) ); // Add WooCommerce params if available if (function_exists('wc_get_cart_url')) { $params['wc_cart_fragments_enabled'] = 'yes' === get_option('woocommerce_enable_ajax_add_to_cart'); $params['wc_cart_hash'] = md5(json_encode(WC()->cart->get_cart())); } wp_localize_script( 'abovewp-atc-popup', 'abovewp_atc_params', $params ); } /** * Add admin menu */ public function add_admin_menu() { add_submenu_page( 'abovewp', __('AboveWP Add To Cart Upsell Popup', 'abovewp-atc-popup-upsell'), __('ATC Upsell Popup', 'abovewp-atc-popup-upsell'), 'manage_options', 'abovewp-atc-popup-upsell', array($this, 'settings_page') ); } /** * Register settings */ public function register_settings() { register_setting('abovewp_atc_settings', 'abovewp_atc_enabled', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_upsell_source', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_global_product_ids', array( 'sanitize_callback' => function ($value) { if (is_array($value)) { $value = array_filter($value); return implode(',', array_map('absint', $value)); } return sanitize_text_field($value); }, )); register_setting('abovewp_atc_settings', 'abovewp_atc_upsell_count', array( 'sanitize_callback' => 'absint', )); register_setting('abovewp_atc_settings', 'abovewp_atc_category_mappings', array( 'sanitize_callback' => function ($value) { if (!is_array($value)) { return array(); } return array_map('sanitize_text_field', $value); }, )); // Text customization settings register_setting('abovewp_atc_settings', 'abovewp_atc_popup_title', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_success_message_format', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_add_to_cart_text', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_view_cart_text', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_checkout_text', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_continue_shopping_text', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_added_to_cart_text', array( 'sanitize_callback' => 'sanitize_text_field', )); // Button visibility settings register_setting('abovewp_atc_settings', 'abovewp_atc_show_view_cart', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_show_checkout', array( 'sanitize_callback' => 'sanitize_text_field', )); register_setting('abovewp_atc_settings', 'abovewp_atc_show_continue_shopping', array( 'sanitize_callback' => 'sanitize_text_field', )); // Color settings register_setting('abovewp_atc_settings', 'abovewp_atc_price_color', array( 'sanitize_callback' => 'sanitize_hex_color', )); register_setting('abovewp_atc_settings', 'abovewp_atc_add_to_cart_button_color', array( 'sanitize_callback' => 'sanitize_hex_color', )); register_setting('abovewp_atc_settings', 'abovewp_atc_view_cart_button_color', array( 'sanitize_callback' => 'sanitize_hex_color', )); register_setting('abovewp_atc_settings', 'abovewp_atc_checkout_button_color', array( 'sanitize_callback' => 'sanitize_hex_color', )); } /** * Settings page */ public function settings_page() { // Get options $enabled = get_option('abovewp_atc_enabled', 'yes'); $upsell_source = get_option('abovewp_atc_upsell_source', 'woo_upsells'); $global_product_ids = get_option('abovewp_atc_global_product_ids', ''); $upsell_count = get_option('abovewp_atc_upsell_count', 2); $category_mappings = get_option('abovewp_atc_category_mappings', array()); // Get all product categories $product_categories = get_terms(array( 'taxonomy' => 'product_cat', 'hide_empty' => false, )); ?>

name); ?>

base) && strpos($current_screen->base, 'abovewp') !== false) { remove_all_actions('admin_notices'); remove_all_actions('all_admin_notices'); } } /** * Add product upsell data */ public function add_product_upsell_data() { global $product; if (!$product) { return; } $upsell_source = get_option('abovewp_atc_upsell_source', 'woo_upsells'); $upsell_count = intval(get_option('abovewp_atc_upsell_count', 2)); // Get upsell products based on selected source $upsell_ids = array(); switch ($upsell_source) { case 'woo_upsells': // Use WooCommerce's built-in upsells $upsell_ids = $product->get_upsell_ids(); break; case 'global_products': // Use globally defined products $global_product_ids = get_option('abovewp_atc_global_product_ids', ''); if (!empty($global_product_ids)) { $upsell_ids = array_map('trim', explode(',', $global_product_ids)); } break; case 'category_based': // Use category-based products $category_mappings = get_option('abovewp_atc_category_mappings', array()); $product_categories = $product->get_category_ids(); foreach ($product_categories as $category_id) { if (isset($category_mappings[$category_id]) && !empty($category_mappings[$category_id])) { $category_upsells = array_map('trim', explode(',', $category_mappings[$category_id])); $upsell_ids = array_merge($upsell_ids, $category_upsells); } } // Remove duplicates $upsell_ids = array_unique($upsell_ids); break; } // Remove current product from upsells if it's there $current_product_id = $product->get_id(); $upsell_ids = array_diff($upsell_ids, array($current_product_id)); // Limit the number of upsells $upsell_ids = array_slice($upsell_ids, 0, $upsell_count); // Prepare upsell products data $upsell_products = array(); foreach ($upsell_ids as $upsell_id) { $upsell_product = wc_get_product($upsell_id); if (!$upsell_product || !$upsell_product->is_purchasable() || !$upsell_product->is_in_stock()) { continue; } $upsell_products[] = array( 'id' => $upsell_product->get_id(), 'name' => $upsell_product->get_name(), 'price' => $upsell_product->get_price(), 'price_html' => $upsell_product->get_price_html(), 'image' => wp_get_attachment_image_url($upsell_product->get_image_id(), 'woocommerce_thumbnail') ?: wc_placeholder_img_src('woocommerce_thumbnail'), 'url' => $upsell_product->get_permalink(), ); } // Prepare data for JavaScript $popup_data = array( 'added_product_name' => $product->get_name(), 'upsell_products' => $upsell_products, ); // Add data to the page for JavaScript if (!empty($upsell_products)) { // We need to make sure this script is added after jQuery and our main script wp_add_inline_script('abovewp-atc-popup', 'var abovewp_atc_upsell_data = ' . wp_json_encode($popup_data) . ';', 'after'); } // Also store data in a transient for AJAX requests set_transient('abovewp_product_' . $current_product_id . '_upsell_data', $popup_data, HOUR_IN_SECONDS); } /** * Add popup HTML to footer */ public function add_popup_html() { // Enhanced page detection - same logic as enqueue_scripts $should_load = false; // Standard WooCommerce pages if (is_product() || is_cart() || is_shop() || is_product_category() || is_product_tag()) { $should_load = true; } // Check for WooCommerce-related content on any page if (!$should_load && (is_page() || is_single() || is_home() || is_front_page())) { // Check for WooCommerce shortcodes or blocks global $post; if ($post && ( has_shortcode($post->post_content, 'product') || has_shortcode($post->post_content, 'products') || has_shortcode($post->post_content, 'recent_products') || has_shortcode($post->post_content, 'featured_products') || has_shortcode($post->post_content, 'sale_products') || has_shortcode($post->post_content, 'best_selling_products') || has_shortcode($post->post_content, 'top_rated_products') || strpos($post->post_content, 'wp:woocommerce/') !== false || strpos($post->post_content, 'add-to-cart') !== false )) { $should_load = true; } } // Check if we're on a page that might have Elementor or other page builder WooCommerce widgets if (!$should_load && function_exists('wc_get_page_id')) { // Also load on pages that might have WooCommerce widgets or custom implementations $should_load = true; // For maximum compatibility } if (!$should_load) { return; } $cart_url = wc_get_cart_url(); $checkout_url = wc_get_checkout_url(); // Get text customization settings $popup_title = get_option('abovewp_atc_popup_title', __('You might also like...', 'abovewp-atc-popup-upsell')); // Get button visibility settings $show_view_cart = get_option('abovewp_atc_show_view_cart', 'yes') === 'yes'; $show_checkout = get_option('abovewp_atc_show_checkout', 'yes') === 'yes'; $show_continue_shopping = get_option('abovewp_atc_show_continue_shopping', 'yes') === 'yes'; // Get button text settings $view_cart_text = get_option('abovewp_atc_view_cart_text', __('View Cart', 'abovewp-atc-popup-upsell')); $checkout_text = get_option('abovewp_atc_checkout_text', __('Checkout', 'abovewp-atc-popup-upsell')); $continue_shopping_text = get_option('abovewp_atc_continue_shopping_text', __('Continue Shopping', 'abovewp-atc-popup-upsell')); // Get color settings $price_color = get_option('abovewp_atc_price_color', '#0582FF'); $add_to_cart_button_color = get_option('abovewp_atc_add_to_cart_button_color', '#0582FF'); $view_cart_button_color = get_option('abovewp_atc_view_cart_button_color', '#0582FF'); $checkout_button_color = get_option('abovewp_atc_checkout_button_color', '#4CAF50'); // Darken colors for hover states (roughly 15% darker) $add_to_cart_hover = $this->darken_color($add_to_cart_button_color, 15); $view_cart_hover = $this->darken_color($view_cart_button_color, 15); $checkout_hover = $this->darken_color($checkout_button_color, 15); $inline_css = " .abovewp-atc-popup-product .price { color: " . esc_attr($price_color) . "; } .abovewp-atc-popup-product button { background-color: " . esc_attr($add_to_cart_button_color) . "; } .abovewp-atc-popup-product button:hover { background-color: " . esc_attr($add_to_cart_hover) . "; } .abovewp-atc-popup-product button.added { background-color: #4CAF50; } .abovewp-atc-popup-actions .view-cart { background-color: " . esc_attr($view_cart_button_color) . "; } .abovewp-atc-popup-actions .view-cart:hover { background-color: " . esc_attr($view_cart_hover) . "; } .abovewp-atc-popup-actions .checkout { background-color: " . esc_attr($checkout_button_color) . "; } .abovewp-atc-popup-actions .checkout:hover { background-color: " . esc_attr($checkout_hover) . "; } "; wp_add_inline_style('abovewp-atc-popup', $inline_css); ?>

cart->add_to_cart($product_id); if ($added) { // Get mini cart fragments $fragments = array(); ob_start(); woocommerce_mini_cart(); $mini_cart = ob_get_clean(); $fragments['div.widget_shopping_cart_content'] = '
' . $mini_cart . '
'; wp_send_json_success(array( 'fragments' => $fragments, )); } else { wp_send_json_error(); } wp_die(); } /** * Add data attributes to add to cart buttons in product loops * This helps identify the product when added via AJAX */ public function add_data_to_add_to_cart_button($args, $product) { // Store product ID in a data attribute $args['attributes']['data-product_id'] = $product->get_id(); // Get and prepare the upsell data for this product $upsell_source = get_option('abovewp_atc_upsell_source', 'woo_upsells'); $upsell_count = intval(get_option('abovewp_atc_upsell_count', 2)); // Get upsell products based on selected source $upsell_ids = array(); switch ($upsell_source) { case 'woo_upsells': // Use WooCommerce's built-in upsells $upsell_ids = $product->get_upsell_ids(); break; case 'global_products': // Use globally defined products $global_product_ids = get_option('abovewp_atc_global_product_ids', ''); if (!empty($global_product_ids)) { $upsell_ids = array_map('trim', explode(',', $global_product_ids)); } break; case 'category_based': // Use category-based products $category_mappings = get_option('abovewp_atc_category_mappings', array()); $product_categories = $product->get_category_ids(); foreach ($product_categories as $category_id) { if (isset($category_mappings[$category_id]) && !empty($category_mappings[$category_id])) { $category_upsells = array_map('trim', explode(',', $category_mappings[$category_id])); $upsell_ids = array_merge($upsell_ids, $category_upsells); } } // Remove duplicates $upsell_ids = array_unique($upsell_ids); break; } // Remove current product from upsells if it's there $current_product_id = $product->get_id(); $upsell_ids = array_diff($upsell_ids, array($current_product_id)); // Limit the number of upsells $upsell_ids = array_slice($upsell_ids, 0, $upsell_count); // Store product and upsell IDs for reference $args['attributes']['data-has-upsells'] = !empty($upsell_ids) ? 'true' : 'false'; // Store data in transient for AJAX requests if (!empty($upsell_ids)) { // Prepare upsell products data $upsell_products = array(); foreach ($upsell_ids as $upsell_id) { $upsell_product = wc_get_product($upsell_id); if (!$upsell_product || !$upsell_product->is_purchasable() || !$upsell_product->is_in_stock()) { continue; } $upsell_products[] = array( 'id' => $upsell_product->get_id(), 'name' => $upsell_product->get_name(), 'price' => $upsell_product->get_price(), 'price_html' => $upsell_product->get_price_html(), 'image' => wp_get_attachment_image_url($upsell_product->get_image_id(), 'woocommerce_thumbnail') ?: wc_placeholder_img_src('woocommerce_thumbnail'), 'url' => $upsell_product->get_permalink(), ); } // Prepare data for JavaScript $popup_data = array( 'added_product_name' => $product->get_name(), 'upsell_products' => $upsell_products, ); // Store data in a transient for AJAX requests set_transient('abovewp_product_' . $current_product_id . '_upsell_data', $popup_data, HOUR_IN_SECONDS); } return $args; } /** * AJAX handler to get upsell data for a product */ public function ajax_get_upsell_data() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'abovewp-atc-upsell')) { wp_send_json_error(array('message' => 'Invalid security token')); return; } // Check if product ID is provided if (!isset($_POST['product_id'])) { wp_send_json_error(array('message' => 'No product ID provided')); return; } $product_id = sanitize_text_field(wp_unslash($_POST['product_id'])); $product = null; // If product_id is 'latest', get the latest added product to cart if ($product_id === 'latest') { // Use our enhanced method to get the last added product $latest_product_id = $this->get_last_added_product(); if ($latest_product_id) { $product_id = $latest_product_id; } else { wp_send_json_error(array('message' => 'No products in cart or recently added')); return; } } // Get product data $product = wc_get_product($product_id); if (!$product) { wp_send_json_error(array('message' => 'Product not found')); return; } // Try to get data from transient first $transient_key = 'abovewp_product_' . $product_id . '_upsell_data'; $upsell_data = get_transient($transient_key); if (!$upsell_data) { // If no transient data, generate it $upsell_data = $this->generate_upsell_data_for_product($product); // Store in transient for future use set_transient($transient_key, $upsell_data, HOUR_IN_SECONDS); } if (empty($upsell_data['upsell_products'])) { wp_send_json_error(array('message' => 'No upsell products found')); return; } wp_send_json_success($upsell_data); } /** * Generate upsell data for a specific product * * @param WC_Product $product The product to generate upsell data for * @return array The upsell data */ private function generate_upsell_data_for_product($product) { $upsell_source = get_option('abovewp_atc_upsell_source', 'woo_upsells'); $upsell_count = intval(get_option('abovewp_atc_upsell_count', 2)); $global_product_ids = get_option('abovewp_atc_global_product_ids', ''); $category_mappings = get_option('abovewp_atc_category_mappings', array()); $upsell_products = array(); $upsell_ids = array(); // Get upsell products based on the selected source switch ($upsell_source) { case 'woo_upsells': // Use WooCommerce's built-in upsells $upsell_ids = $product->get_upsell_ids(); break; case 'global_products': // Use globally defined products if (!empty($global_product_ids)) { $upsell_ids = array_map('trim', explode(',', $global_product_ids)); } break; case 'category_based': // Use category-based products $product_categories = $product->get_category_ids(); foreach ($product_categories as $category_id) { if (isset($category_mappings[$category_id]) && !empty($category_mappings[$category_id])) { $category_upsells = array_map('trim', explode(',', $category_mappings[$category_id])); $upsell_ids = array_merge($upsell_ids, $category_upsells); } } // Remove duplicates $upsell_ids = array_unique($upsell_ids); break; } // Remove current product from upsells if it's there $current_product_id = $product->get_id(); $upsell_ids = array_diff($upsell_ids, array($current_product_id)); // Limit the number of upsells $upsell_ids = array_slice($upsell_ids, 0, $upsell_count); // Prepare upsell data foreach ($upsell_ids as $upsell_id) { $upsell_product = wc_get_product($upsell_id); if (!$upsell_product || !$upsell_product->is_purchasable() || !$upsell_product->is_in_stock()) { continue; } $upsell_products[] = array( 'id' => $upsell_product->get_id(), 'name' => $upsell_product->get_name(), 'price' => $upsell_product->get_price(), 'price_html' => $upsell_product->get_price_html(), 'image' => wp_get_attachment_image_url($upsell_product->get_image_id(), 'woocommerce_thumbnail') ?: wc_placeholder_img_src('woocommerce_thumbnail'), 'url' => get_permalink($upsell_product->get_id()) ); } return array( 'added_product_name' => $product->get_name(), 'upsell_products' => $upsell_products ); } /** * AJAX handler for searching products (admin settings page) */ public function ajax_search_products() { check_ajax_referer('abovewp_atc_search_products', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error('Unauthorized'); } $term = isset($_GET['term']) ? sanitize_text_field(wp_unslash($_GET['term'])) : ''; if (empty($term)) { wp_send_json(array('results' => array())); } $products = wc_get_products(array( 's' => $term, 'limit' => 30, 'status' => 'publish', )); $results = array(); foreach ($products as $product) { $image_url = ''; $image_id = $product->get_image_id(); if ($image_id) { $image_src = wp_get_attachment_image_src($image_id, 'thumbnail'); if ($image_src) { $image_url = $image_src[0]; } } else { $image_url = wc_placeholder_img_src('thumbnail'); } $results[] = array( 'id' => $product->get_id(), 'text' => $product->get_name(), 'image' => $image_url, 'price_html' => wp_strip_all_tags($product->get_price_html()), ); } wp_send_json(array('results' => $results)); } /** * Hook into WooCommerce add to cart action for better detection */ public function on_product_added_to_cart($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart) { // Store the last added product in session for JavaScript to pick up WC()->session->set('abovewp_last_added_product', $product_id); WC()->session->set('abovewp_last_added_time', time()); // Also store in transient as fallback set_transient('abovewp_last_added_product_' . WC()->session->get_customer_id(), $product_id, 300); // 5 minutes } /** * Add method to retrieve last added product for AJAX calls */ public function get_last_added_product() { // Try session first $product_id = WC()->session->get('abovewp_last_added_product'); $time = WC()->session->get('abovewp_last_added_time'); // Only return if added recently (within 5 minutes) if ($product_id && $time && (time() - $time < 300)) { return $product_id; } // Try transient as fallback $product_id = get_transient('abovewp_last_added_product_' . WC()->session->get_customer_id()); if ($product_id) { return $product_id; } // As last resort, get the most recent item from cart $cart = WC()->cart->get_cart(); if (!empty($cart)) { $cart_keys = array_keys($cart); $last_key = end($cart_keys); return $cart[$last_key]['product_id']; } return null; } /** * Add cart monitoring script */ public function add_cart_monitoring_script() { if (!wp_script_is('abovewp-atc-popup', 'enqueued')) { return; } // Add cart state monitoring $cart_contents = absint(WC()->cart->get_cart_contents_count()); $cart_hash = esc_js(WC()->cart->get_cart_hash()); $script = " if (typeof window.abovewp_cart_state === 'undefined') { window.abovewp_cart_state = { item_count: {$cart_contents}, cart_hash: '{$cart_hash}' }; } "; // Check if a product was just added to cart (non-AJAX flow) $last_product_id = WC()->session->get('abovewp_last_added_product'); $last_added_time = WC()->session->get('abovewp_last_added_time'); if ($last_product_id && $last_added_time && (time() - $last_added_time < 30)) { $product = wc_get_product($last_product_id); if ($product) { $upsell_data = $this->generate_upsell_data_for_product($product); if (!empty($upsell_data['upsell_products'])) { $script .= "\nwindow.abovewp_atc_upsell_data = " . wp_json_encode($upsell_data) . ";\n"; $script .= "window.abovewp_atc_show_popup_on_load = true;\n"; } } // Clear the session flag so it doesn't fire again on next page load WC()->session->set('abovewp_last_added_product', null); WC()->session->set('abovewp_last_added_time', null); } wp_add_inline_script('abovewp-atc-popup', $script, 'before'); } } // Initialize the plugin $abovewp_atc_popup_upsell = new AboveWP_ATC_Popup_Upsell();