.aieo-pro-badge){position:relative}' . $gallery . '>.aieo-pro-badge{position:absolute;z-index:2;inset-block-start:' . $inset . ';inset-inline-start:' . $inset . '}' . $gallery . '>.aieo-pro-badge:has(~.aieo-new-badge--single),' . $gallery . '>.aieo-new-badge--single~.aieo-pro-badge{inset-block-start:calc(' . $inset . ' + 2.2rem)}'; } public function add_badge_layout_body_class($classes) { $position = AIEO_DMM_Settings::get('archive_badge_position', 'image_top_left'); if ($position === 'below_favourite') { $classes[] = 'aieo-badges-below-fav'; } return $classes; } const HAS_PRICING_BULK_THRESHOLD = 12; private $has_pricing_index = null; private $has_pricing_cache_probed = false; private $has_pricing_probe = array(); private function pricing_engine() { if (!class_exists('AIEO_DMM_Pricing_Engine') || !is_callable(array('AIEO_DMM_Pricing_Engine', 'instance'))) { return null; } $engine = AIEO_DMM_Pricing_Engine::instance(); return is_object($engine) ? $engine : null; } private $role_prices_memo = array(); private function role_pricing_table() { global $wpdb; return $wpdb->prefix . 'aieo_dmm_role_prices'; } public static function has_role_pricing($product_id) { static $shared = null; if ($shared === null) { $shared = new self(); } return $shared->product_has_role_pricing($product_id); } private function product_has_role_pricing($product_id) { $product_id = (int) $product_id; if ($product_id <= 0) { return false; } if (!is_array($this->has_pricing_index) && !$this->has_pricing_cache_probed) { $this->has_pricing_cache_probed = true; $cached = wp_cache_get($this->has_pricing_cache_key(), 'aieo_dmm'); if (is_array($cached)) { $this->has_pricing_index = $cached; } } if (is_array($this->has_pricing_index)) { return isset($this->has_pricing_index[$product_id]); } if (isset($this->has_pricing_probe[$product_id])) { return $this->has_pricing_probe[$product_id]; } if (count($this->has_pricing_probe) < self::HAS_PRICING_BULK_THRESHOLD) { global $wpdb; $table = $this->role_pricing_table(); $exists = (bool) $wpdb->get_var($wpdb->prepare( "SELECT 1 FROM {$table} WHERE product_id = %d OR parent_id = %d LIMIT 1", $product_id, $product_id )); $this->has_pricing_probe[$product_id] = $exists; return $exists; } $index = $this->get_has_pricing_index(); return isset($index[$product_id]); } private function has_pricing_cache_key() { return 'role_pricing_index_' . self::get_role_prices_version(); } private function get_has_pricing_index() { if (is_array($this->has_pricing_index)) { return $this->has_pricing_index; } $key = $this->has_pricing_cache_key(); $cached = wp_cache_get($key, 'aieo_dmm'); if (is_array($cached)) { $this->has_pricing_index = $cached; return $this->has_pricing_index; } global $wpdb; $table = $this->role_pricing_table(); $rows = $wpdb->get_results("SELECT product_id, parent_id FROM {$table}", ARRAY_A); if ('' !== $wpdb->last_error) { return array(); } $index = array(); foreach ((array) $rows as $row) { $index[(int) $row['product_id']] = true; $parent = (int) $row['parent_id']; if ($parent > 0) { $index[$parent] = true; } } $this->has_pricing_index = $index; wp_cache_set($key, $index, 'aieo_dmm', HOUR_IN_SECONDS); return $index; } private function get_role_prices_for_product($product_id) { $product_id = (int) $product_id; if ($product_id <= 0) { return array(); } if (isset($this->role_prices_memo[$product_id])) { return $this->role_prices_memo[$product_id]; } $engine = $this->pricing_engine(); if ($engine && is_callable(array($engine, 'get_cached_role_prices'))) { $shared = $engine->get_cached_role_prices($product_id); if (is_array($shared)) { $this->role_prices_memo[$product_id] = $shared; return $shared; } } global $wpdb; $table = $this->role_pricing_table(); $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE product_id = %d", $product_id), ARRAY_A); $out = array(); if (is_array($row)) { foreach ($row as $col => $val) { if (strpos($col, 'role_') !== 0) { continue; } if ($col === 'role_prices') { continue; } if ($val === null || $val === '') { continue; } $price = (float) $val; if ($price > 0) { $out[substr($col, 5)] = $price; } } } $this->role_prices_memo[$product_id] = $out; return $out; } private function product_has_real_public_sale($product) { if (!$product || !is_object($product) || !method_exists($product, 'get_id')) { return false; } $check = static function ($pid) { $raw_sale = get_post_meta((int) $pid, '_sale_price', true); if ($raw_sale === '' || $raw_sale === null) { return false; } $sale = (float) $raw_sale; if ($sale <= 0) { return false; } $raw_reg = get_post_meta((int) $pid, '_regular_price', true); if ($raw_reg === '' || $raw_reg === null) { return false; } return $sale < (float) $raw_reg; }; if (method_exists($product, 'is_type') && $product->is_type('variable')) { foreach ((array) $product->get_children() as $vid) { if ($check($vid)) { return true; } } return $check($product->get_id()); } return $check($product->get_id()); } private function current_user_is_pro() { if (!is_user_logged_in()) { return false; } if (class_exists('AIEO_DMM_Pricing_Engine') && AIEO_DMM_Pricing_Engine::role_pricing_suppressed()) { return false; } $user = wp_get_current_user(); if (!$user || empty($user->roles)) { return false; } $enabled = (array) AIEO_DMM_Settings::get('enabled_roles', array()); if (empty($enabled)) { return false; } foreach ((array) $user->roles as $r) { if (in_array($r, $enabled, true)) { return true; } } return false; } private function best_real_public_sale($product) { if (!$product || !is_object($product)) { return null; } $best = null; $consider = static function ($pid) use (&$best) { $raw_sale = get_post_meta((int) $pid, '_sale_price', true); if ($raw_sale === '' || $raw_sale === null) { return; } $sale = (float) $raw_sale; if ($sale <= 0) { return; } $raw_reg = get_post_meta((int) $pid, '_regular_price', true); if ($raw_reg === '' || $raw_reg === null) { return; } if ($sale >= (float) $raw_reg) { return; } if ($best === null || $sale < $best) { $best = $sale; } }; if (method_exists($product, 'is_type') && $product->is_type('variable')) { foreach ((array) $product->get_children() as $vid) { $consider($vid); } $consider($product->get_id()); } else { $consider($product->get_id()); } return $best; } private function best_role_price_for_current_user($product) { if (!$product || !is_object($product)) { return null; } if (!$this->current_user_is_pro()) { return null; } $user = wp_get_current_user(); $user_roles = $user && !empty($user->roles) ? (array) $user->roles : array(); if (empty($user_roles)) { return null; } $best = null; $self = $this; $consider = static function ($pid) use (&$best, $self, $user_roles) { $prices = $self->get_role_prices_for_product_public((int) $pid); if (empty($prices)) { return; } foreach ($user_roles as $role) { $sanitized = strtolower(preg_replace('/[^a-z0-9_]/i', '_', (string) $role)); if (isset($prices[$sanitized]) && (float) $prices[$sanitized] > 0) { $p = (float) $prices[$sanitized]; if ($best === null || $p < $best) { $best = $p; } } if (isset($prices[$role]) && (float) $prices[$role] > 0) { $p = (float) $prices[$role]; if ($best === null || $p < $best) { $best = $p; } } } }; if (method_exists($product, 'is_type') && $product->is_type('variable')) { $children = (array) $product->get_children(); $engine = $this->pricing_engine(); if ($engine && is_callable(array($engine, 'warm_role_price_family'))) { $engine->warm_role_price_family($product->get_id(), $children); } foreach ($children as $vid) { $consider($vid); } $consider($product->get_id()); } else { $consider($product->get_id()); } return $best; } public function get_role_prices_for_product_public($product_id) { return $this->get_role_prices_for_product($product_id); } private $in_price_filter = false; public function filter_role_price($price, $product) { if ($this->in_price_filter) { return $price; } if (!$product || !is_object($product) || !is_numeric($price) || (float) $price <= 0) { return $price; } if (!$this->current_user_is_pro()) { return $price; } $this->in_price_filter = true; $best = $this->best_role_price_for_current_user($product); $this->in_price_filter = false; if ($best === null || $best <= 0) { return $price; } $public = (float) $price; return ($best < $public) ? $best : $price; } public function modify_variation_hash($hash, $product, $for_display) { if (!is_user_logged_in()) { return $hash; } if (class_exists('AIEO_DMM_Pricing_Engine') && AIEO_DMM_Pricing_Engine::role_pricing_suppressed()) { return $hash; } $u = wp_get_current_user(); $roles = $u && !empty($u->roles) ? (array) $u->roles : array(); if (empty($roles)) { return $hash; } $enabled = (array) AIEO_DMM_Settings::get('enabled_roles', array()); $pricing_roles = array_values(array_intersect($roles, $enabled)); if (empty($pricing_roles)) { return $hash; } sort($pricing_roles); if (!is_array($hash)) { $hash = (array) $hash; } $hash['aieo_role'] = md5(implode('|', $pricing_roles)); $hash['aieo_rpv'] = self::get_role_prices_version(); return $hash; } public static function get_role_prices_version() { return (string) get_option(self::ROLE_PRICES_VERSION_OPTION, '0'); } public static function bump_role_prices_version() { $current = (string) get_option(self::ROLE_PRICES_VERSION_OPTION, '0'); $next = (string) time(); if ($next === $current) { $next .= '.1'; } wp_cache_delete('role_pricing_index_' . $current, 'aieo_dmm'); update_option(self::ROLE_PRICES_VERSION_OPTION, $next, true); return $next; } public function apply_cart_role_prices($cart) { if (!is_a($cart, 'WC_Cart')) { return; } if (!$this->current_user_is_pro()) { return; } if (did_action('woocommerce_before_calculate_totals') >= 2 && doing_filter('woocommerce_calculate_totals')) { return; } foreach ($cart->get_cart() as $item) { if (!isset($item['data']) || !is_object($item['data'])) { continue; } $product = $item['data']; $best = $this->best_role_price_for_current_user($product); if ($best === null || $best <= 0) { continue; } $current = (float) $product->get_price('edit'); if ($best < $current || $current <= 0) { $product->set_price($best); } } } private function should_suppress_sale_badge($product) { if (!$product || !is_object($product)) { return false; } $has_role = $this->product_has_role_pricing((int) $product->get_id()); if (!$has_role) { return false; } $public_sale = $this->best_real_public_sale($product); if ($public_sale === null) { return true; } if (!$this->current_user_is_pro()) { return false; } $role_price = $this->best_role_price_for_current_user($product); if ($role_price === null) { return false; } return $role_price < $public_sale; } private function should_suppress_pro_badge($product) { if (!$product || !is_object($product)) { return true; } if (!$this->product_has_role_pricing((int) $product->get_id())) { return true; } if (!$this->current_user_is_pro()) { return false; } $public_sale = $this->best_real_public_sale($product); if ($public_sale === null) { return false; } $role_price = $this->best_role_price_for_current_user($product); if ($role_price === null) { return false; } return $role_price >= $public_sale; } public function show_pro_price_as_sale($price_html, $product) { if (!is_a($product, 'WC_Product') || !$this->current_user_is_pro()) { return $price_html; } if ($product->is_type('variable') || $product->is_type('grouped')) { return $price_html; } $role_price = $this->best_role_price_for_current_user($product); if ($role_price === null || (float) $role_price <= 0) { return $price_html; } $public_regular = (float) str_replace(',', '.', (string) get_post_meta((int) $product->get_id(), '_regular_price', true)); if ($public_regular <= 0 || (float) $role_price >= $public_regular) { return $price_html; } if (abs((float) $product->get_price() - (float) $role_price) > 0.0001) { return $price_html; } $reg_display = wc_get_price_to_display($product, array('price' => $public_regular)); $role_display = wc_get_price_to_display($product, array('price' => (float) $role_price)); return wc_format_sale_price($reg_display, $role_display) . $product->get_price_suffix(); } public function maybe_suppress_sale_flash($html, $post, $product) { return $this->should_suppress_sale_badge($product) ? '' : $html; } public function rewire_login_message_renderer() { if (!class_exists('OM_Role_Login_Message') || !class_exists('OM_Role_Price_Handler')) { return; } $msg = OM_Role_Login_Message::instance(OM_Role_Price_Handler::instance()); if (!is_object($msg)) { return; } remove_filter('woocommerce_get_price_html', array($msg, 'add_login_message'), 99); } public function append_login_message_to_price($price_html, $product) { if (is_user_logged_in()) { return $price_html; } if (empty(AIEO_DMM_Settings::get('show_login_message', false))) { return $price_html; } if (!$product || !is_a($product, 'WC_Product')) { return $price_html; } if (!$this->product_has_role_pricing((int) $product->get_id())) { return $price_html; } if (!empty($GLOBALS['aieo_satc_suppress_login_message'])) { return $price_html; } $is_single = (function_exists('is_product') && is_product()); if ($is_single && self::login_in_cluster()) { return $price_html; } $key = $is_single ? 'login_message_text' : 'login_message_archive'; $raw = (string) AIEO_DMM_Settings::get($key, ''); if ($raw === '') { return $price_html; } $login_url = function_exists('wc_get_page_permalink') ? (string) wc_get_page_permalink('myaccount') : wp_login_url(); $raw = str_replace('{login_url}', esc_url($login_url), $raw); $custom_class = (string) AIEO_DMM_Settings::get('login_message_css_class', ''); $classes = 'om-role-login-message ' . ($is_single ? 'om-login-message-single' : 'om-login-message-archive'); if ($custom_class !== '') { $classes .= ' ' . $custom_class; } return $price_html . sprintf( '%s', esc_attr($classes), $raw ); } public function print_login_message_css() { if (is_user_logged_in()) { return; } if (empty(AIEO_DMM_Settings::get('show_login_message', false))) { return; } $color = (string) sanitize_hex_color((string) AIEO_DMM_Settings::get('login_message_color', '')); $ad = (int) AIEO_DMM_Settings::get('login_message_font_archive_desktop', 0); $am = (int) AIEO_DMM_Settings::get('login_message_font_archive_mobile', 0); $sd = (int) AIEO_DMM_Settings::get('login_message_font_single_desktop', 0); $sm = (int) AIEO_DMM_Settings::get('login_message_font_single_mobile', 0); if ($color === '' && $ad <= 0 && $am <= 0 && $sd <= 0 && $sm <= 0) { return; } $css = ''; if ($color !== '') { $css .= '.om-role-login-message a{color:' . $color . '}'; } if ($ad > 0) { $css .= '.om-login-message-archive,.om-login-message-archive a{font-size:' . $ad . 'px}'; } if ($sd > 0) { $css .= '.om-login-message-single,.om-login-message-single a{font-size:' . $sd . 'px}'; } $mq = ''; if ($am > 0) { $mq .= '.om-login-message-archive,.om-login-message-archive a{font-size:' . $am . 'px}'; } if ($sm > 0) { $mq .= '.om-login-message-single,.om-login-message-single a{font-size:' . $sm . 'px}'; } if ($mq !== '') { $css .= '@media(max-width:768px){' . $mq . '}'; } echo ''; } public function render_login_modal() { if (is_user_logged_in()) { return; } if (empty(AIEO_DMM_Settings::get('show_login_message', false))) { return; } if (empty(AIEO_DMM_Settings::get('login_message_modal_enabled', false))) { return; } if (function_exists('is_account_page') && is_account_page()) { return; } $is_ctx = (function_exists('is_woocommerce') && is_woocommerce()) || (function_exists('is_shop') && is_shop()) || is_front_page() || is_home(); if (!$is_ctx) { return; } $current = esc_url_raw(home_url(wp_unslash($_SERVER['REQUEST_URI'] ?? '/'))); $login_html = ''; if (function_exists('woocommerce_login_form')) { ob_start(); woocommerce_login_form(array('redirect' => $current)); $login_html = (string) ob_get_clean(); } $sso_html = class_exists('AIEO_Runtime_SSO_Buttons') ? (string) AIEO_Runtime_SSO_Buttons::render('login', array( 'layout' => 'stacked', 'intro' => __('Or sign in with:', 'ai-eshop-optimizer'), )) : ''; $rich = (string) AIEO_DMM_Settings::get('login_message_modal_content', ''); if ($login_html === '' && $sso_html === '' && trim($rich) === '') { return; } ?> 20, 'height' => 20, 'class' => 'aieo-rolelogin-modal__close-icon')); if ('' !== $icon) { return $icon; } } return class_exists('AIEO_Icons') ? AIEO_Icons::svg('x', '20px') : ''; } public static function login_in_cluster() { $o = get_option('aieo_dmm_role_pricing_login_settings', array()); return is_array($o) && !empty($o['enabled']); } public function render_cluster_login_message() { if (!self::login_in_cluster()) { return; } if (is_user_logged_in()) { return; } if (empty(AIEO_DMM_Settings::get('show_login_message', false))) { return; } if (!function_exists('is_product') || !is_product()) { return; } global $product; if (!$product || !is_a($product, 'WC_Product')) { $product = wc_get_product(get_the_ID()); } if (!$product || !is_a($product, 'WC_Product')) { return; } if (!$this->product_has_role_pricing((int) $product->get_id())) { return; } $raw = (string) AIEO_DMM_Settings::get('login_message_text', ''); if ($raw === '') { return; } $login_url = function_exists('wc_get_page_permalink') ? (string) wc_get_page_permalink('myaccount') : wp_login_url(); $raw = str_replace('{login_url}', esc_url($login_url), $raw); $custom_class = (string) AIEO_DMM_Settings::get('login_message_css_class', ''); $classes = 'om-role-login-message om-login-message-single om-login-message-cluster' . ($custom_class !== '' ? ' ' . $custom_class : ''); echo '' . $raw . ''; } public function maybe_suppress_om_ppe_sale_label($display, $product, $rule) { if (!$display) { return $display; } if ($rule !== 'products_on_sale') { return $display; } return $this->should_suppress_sale_badge($product) ? false : $display; } public function render_archive_pro_badge() { global $product; if (!$product || !is_a($product, 'WC_Product')) { return; } if (class_exists('AIEO_DMM_Badge_Renderer') && AIEO_DMM_Badge_Renderer::picture_carries($product->get_id())) { return; } echo $this->archive_pro_badge_html($product); } public function archive_pro_badge_html($product) { if (class_exists('AIEO_DMM_Badge_Renderer') && AIEO_DMM_Badge_Renderer::is_enabled()) { return ''; } if (!$product || !is_a($product, 'WC_Product') || $this->should_suppress_pro_badge($product)) { return ''; } self::pro_badge_style(); return $this->pro_badge_html(); } private function pro_badge_html() { $label = apply_filters('aieo_dmm_pro_badge_label', __('PRO', 'ai-eshop-optimizer')); $tooltip = apply_filters( 'aieo_dmm_pro_badge_tooltip', __('This product has special pricing for professionals', 'ai-eshop-optimizer') ); return '' . '' . '' . esc_html($label) . '' . ''; } public function render_single_pro_badge() { if (class_exists('AIEO_DMM_Badge_Renderer') && AIEO_DMM_Badge_Renderer::is_enabled()) { return; } $html = $this->build_single_pro_badge_html(); if ($html !== '') { echo $html; } } private function build_single_pro_badge_html() { global $product; if (!$product || !is_a($product, 'WC_Product')) { return ''; } if ($this->should_suppress_pro_badge($product)) { return ''; } return $this->pro_badge_html(); } public function inject_pro_badge_into_gallery($block_content, $block) { if (class_exists('AIEO_DMM_Badge_Renderer') && AIEO_DMM_Badge_Renderer::is_enabled()) { return $block_content; } if (!is_singular('product')) { return $block_content; } $badge = $this->build_single_pro_badge_html(); if ($badge === '') { return $block_content; } if (preg_match('/^(\s*<[a-zA-Z][^>]*>)(.*)$/s', (string) $block_content, $m)) { return $m[1] . $badge . $m[2]; } return $badge . $block_content; } public function render_subtab() { $per_page = 25; $current_page = isset($_GET['paged']) ? max(1, (int) $_GET['paged']) : 1; $this->render_template('role-pricing.php', array( 'settings' => AIEO_DMM_Settings::get_all(), 'all_roles' => $this->get_available_roles(), 'total_rows' => $this->count_priced_rows(), 'price_rows' => $this->fetch_priced_rows($per_page, $current_page), 'per_page' => $per_page, 'current_page' => $current_page, 'gf_forms' => $this->gf_available_forms_for_select(), 'gf_active' => class_exists('GFAPI'), 'gf_samples_url' => plugins_url('assets/samples/', AIEO_FILE), )); } private function gf_available_forms_for_select() { if (!class_exists('GFAPI')) { return array(); } $forms = GFAPI::get_forms(true, false); $out = array(); if (is_array($forms)) { foreach ($forms as $f) { if (isset($f['id'])) { $out[] = array( 'id' => (int) $f['id'], 'title' => isset($f['title']) ? (string) $f['title'] : ('Form #' . (int) $f['id']), ); } } } return $out; } public function ajax_fetch_rows() { AIEO_DMM::verify_ajax_request(); global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_role_prices'; if (!aieo_dmm_table_exists($table)) { wp_send_json_success(array('rows' => array(), 'total' => 0, 'filtered' => 0, 'columns' => array())); } $enabled_roles = AIEO_DMM_Settings::get('enabled_roles', array()); $role_cols = array(); foreach ($enabled_roles as $role) { $role_cols[$role] = aieo_dmm_sanitize_role_column($role); } $page = isset($_POST['page']) ? max(1, absint($_POST['page'])) : 1; $per_page = isset($_POST['per_page']) ? min(200, max(10, absint($_POST['per_page']))) : 25; $search = isset($_POST['search']) ? trim(sanitize_text_field(wp_unslash($_POST['search']))) : ''; $only_nonempty = !empty($_POST['only_nonempty']); $sort_col_req = isset($_POST['sort']) ? sanitize_key(wp_unslash($_POST['sort'])) : 'product_id'; $dir_req = isset($_POST['dir']) && sanitize_key(wp_unslash($_POST['dir'])) === 'desc' ? 'DESC' : 'ASC'; $allowed_sort = array('product_id' => 'product_id', 'sku' => 'sku', 'product_type' => 'product_type'); foreach ($role_cols as $role => $col) { $allowed_sort[$role] = $col; } $sort_col = isset($allowed_sort[$sort_col_req]) ? $allowed_sort[$sort_col_req] : 'product_id'; $where = array('1=1'); $params = array(); if ($search !== '') { $where[] = '(sku LIKE %s OR CAST(product_id AS CHAR) LIKE %s)'; $like = '%' . $wpdb->esc_like($search) . '%'; $params[] = $like; $params[] = $like; } if ($only_nonempty && !empty($role_cols)) { $non_null = array(); foreach ($role_cols as $col) { $non_null[] = "(`{$col}` IS NOT NULL AND `{$col}` > 0)"; } $where[] = '(' . implode(' OR ', $non_null) . ')'; } $where_sql = 'WHERE ' . implode(' AND ', $where); $total = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table}"); $filtered_sql = "SELECT COUNT(*) FROM {$table} {$where_sql}"; $filtered = (int) $wpdb->get_var(empty($params) ? $filtered_sql : $wpdb->prepare($filtered_sql, $params)); $offset = ($page - 1) * $per_page; $data_sql = "SELECT * FROM {$table} {$where_sql} ORDER BY `{$sort_col}` {$dir_req} LIMIT %d OFFSET %d"; $data_params = array_merge($params, array($per_page, $offset)); $rows = $wpdb->get_results($wpdb->prepare($data_sql, $data_params), ARRAY_A); if (!is_array($rows)) { $rows = array(); } $columns = array( array('key' => 'product_id', 'label' => __('Product ID', 'ai-eshop-optimizer'), 'sortable' => true, 'editable' => false), array('key' => 'sku', 'label' => __('SKU', 'ai-eshop-optimizer'), 'sortable' => true, 'editable' => false), array('key' => 'product_type', 'label' => __('Type', 'ai-eshop-optimizer'), 'sortable' => true, 'editable' => false), ); foreach ($enabled_roles as $role) { $columns[] = array('key' => $role, 'label' => $role, 'sortable' => true, 'editable' => true); } $out = array(); foreach ($rows as $r) { $item = array( 'product_id' => (int) $r['product_id'], 'sku' => (string) ($r['sku'] ?? ''), 'product_type' => (string) ($r['product_type'] ?? ''), ); foreach ($role_cols as $role => $col) { $item[$role] = (isset($r[$col]) && $r[$col] !== null) ? (float) $r[$col] : null; } $out[] = $item; } wp_send_json_success(array( 'columns' => $columns, 'rows' => $out, 'total' => $total, 'filtered' => $filtered, 'page' => $page, 'per_page' => $per_page, )); } public function ajax_save_cell() { AIEO_DMM::verify_ajax_request(); $product_id = isset($_POST['product_id']) ? absint(wp_unslash($_POST['product_id'])) : 0; $role = isset($_POST['role']) ? sanitize_key(wp_unslash($_POST['role'])) : ''; $raw_value = isset($_POST['value']) ? trim(sanitize_text_field(wp_unslash($_POST['value']))) : ''; if ($product_id <= 0 || $role === '') { wp_send_json_error(array('message' => __('Missing product_id or role.', 'ai-eshop-optimizer'))); } $enabled_roles = AIEO_DMM_Settings::get('enabled_roles', array()); if (!in_array($role, $enabled_roles, true)) { wp_send_json_error(array('message' => __('That role is not enabled.', 'ai-eshop-optimizer'))); } $is_empty = $raw_value === '' || $raw_value === '-'; if (!$is_empty) { $val = str_replace(',', '.', $raw_value); if (!is_numeric($val) || (float) $val < 0) { wp_send_json_error(array('message' => __('Value must be a non-negative number.', 'ai-eshop-optimizer'))); } $val = (float) $val; } else { $val = null; } $col = aieo_dmm_sanitize_role_column($role); global $wpdb; $tables = array( $wpdb->prefix . 'aieo_dmm_role_prices', $wpdb->prefix . 'om_role_based_pricing', ); foreach ($tables as $table) { if (!aieo_dmm_table_exists($table)) { continue; } $exists = $wpdb->get_var($wpdb->prepare( "SELECT 1 FROM {$table} WHERE product_id = %d LIMIT 1", $product_id )); if ($exists) { $wpdb->query($wpdb->prepare( "UPDATE {$table} SET `{$col}` = " . ($is_empty ? 'NULL' : '%f') . " WHERE product_id = %d", $is_empty ? array($product_id) : array($val, $product_id) )); } else { $product = function_exists('wc_get_product') ? wc_get_product($product_id) : null; $sku = $product ? (string) $product->get_sku() : ''; $parent_id = $product && $product->is_type('variation') ? (int) $product->get_parent_id() : $product_id; $type = $product && $product->is_type('variation') ? 'variation' : 'simple'; $insert = array( 'product_id' => $product_id, 'parent_id' => $parent_id, 'product_type' => $type, 'sku' => $sku, ); $fmt = array('%d', '%d', '%s', '%s'); if (!$is_empty) { $insert[$col] = $val; $fmt[] = '%f'; } $wpdb->insert($table, $insert, $fmt); } } AIEO_DMM_Cache::bump_version('prices'); self::bump_role_prices_version(); wp_send_json_success(array( 'product_id' => $product_id, 'role' => $role, 'value' => $is_empty ? null : $val, )); } public function get_available_roles() { if (!function_exists('get_editable_roles')) { require_once ABSPATH . 'wp-admin/includes/user.php'; } $roles = get_editable_roles(); $out = array(); foreach ($roles as $slug => $data) { if ($slug === 'administrator') { continue; } $out[$slug] = isset($data['name']) ? translate_user_role($data['name']) : $slug; } return $out; } public function ajax_save_settings() { AIEO_DMM::verify_ajax_request(); $raw_roles = isset($_POST['enabled_roles']) && is_array($_POST['enabled_roles']) ? array_map('sanitize_key', wp_unslash($_POST['enabled_roles'])) : array(); $roles = array(); foreach ($raw_roles as $r) { $k = sanitize_key($r); if ($k !== '' && $k !== 'administrator') { $roles[] = $k; } } $badge_position = isset($_POST['archive_badge_position']) ? sanitize_key(wp_unslash($_POST['archive_badge_position'])) : 'image_top_left'; if (!in_array($badge_position, array('image_top_left', 'below_favourite'), true)) { $badge_position = 'image_top_left'; } AIEO_DMM_Settings::update(array( 'enabled_roles' => $roles, 'show_login_message' => !empty($_POST['show_login_message']), 'login_message_text' => isset($_POST['login_message_text']) ? wp_kses_post(wp_unslash($_POST['login_message_text'])) : '', 'login_message_archive' => isset($_POST['login_message_archive']) ? wp_kses_post(wp_unslash($_POST['login_message_archive'])) : '', 'login_message_css_class'=> isset($_POST['login_message_css_class']) ? sanitize_html_class(wp_unslash($_POST['login_message_css_class']), '') : '', 'login_message_color' => isset($_POST['login_message_color']) ? (string) sanitize_hex_color(wp_unslash($_POST['login_message_color'])) : '', 'login_message_font_archive_desktop' => isset($_POST['login_message_font_archive_desktop']) ? max(0, min(72, (int) $_POST['login_message_font_archive_desktop'])) : 0, 'login_message_font_archive_mobile' => isset($_POST['login_message_font_archive_mobile']) ? max(0, min(72, (int) $_POST['login_message_font_archive_mobile'])) : 0, 'login_message_font_single_desktop' => isset($_POST['login_message_font_single_desktop']) ? max(0, min(72, (int) $_POST['login_message_font_single_desktop'])) : 0, 'login_message_font_single_mobile' => isset($_POST['login_message_font_single_mobile']) ? max(0, min(72, (int) $_POST['login_message_font_single_mobile'])) : 0, 'login_message_modal_enabled' => !empty($_POST['login_message_modal_enabled']), 'login_message_modal_content' => isset($_POST['login_message_modal_content']) ? wp_kses_post(wp_unslash($_POST['login_message_modal_content'])) : '', 'mini_cart_badge_icon' => isset($_POST['mini_cart_badge_icon']) ? wp_kses_post(wp_unslash($_POST['mini_cart_badge_icon'])) : '', 'mini_cart_badge_text' => isset($_POST['mini_cart_badge_text']) ? sanitize_text_field(wp_unslash($_POST['mini_cart_badge_text'])) : '', 'mini_cart_badge_alt' => isset($_POST['mini_cart_badge_alt']) ? wp_kses_post(wp_unslash($_POST['mini_cart_badge_alt'])) : '', 'wpdatatables_table_id' => isset($_POST['wpdatatables_table_id']) ? absint(wp_unslash($_POST['wpdatatables_table_id'])) : 0, 'archive_badge_position' => $badge_position, )); update_option('aieo_dmm_role_pricing_login_settings', array( 'enabled' => !empty($_POST['login_message_in_cluster']), ), false); if (function_exists('aieo_dmm_sync_role_columns')) { aieo_dmm_sync_role_columns($roles); } AIEO_DMM_Settings::sync_legacy_role_pricing_option(); AIEO_DMM_Cache::bump_version('prices'); self::bump_role_prices_version(); wp_send_json_success(array( 'message' => __('Settings saved.', 'ai-eshop-optimizer'), 'enabled_roles' => $roles, )); } public function ajax_upload_csv() { AIEO_DMM::verify_ajax_request(); if (empty($_FILES['csv_file']) || !isset($_FILES['csv_file']['tmp_name'])) { wp_send_json_error(array('message' => __('No file received.', 'ai-eshop-optimizer'))); } $mode = isset($_POST['mode']) && sanitize_key(wp_unslash($_POST['mode'])) === 'overwrite' ? 'overwrite' : 'merge'; $file = $_FILES['csv_file']; $tmp = isset($file['tmp_name']) ? $file['tmp_name'] : ''; if (!is_uploaded_file($tmp)) { wp_send_json_error(array('message' => __('Upload validation failed.', 'ai-eshop-optimizer'))); } $raw = file_get_contents($tmp); if (is_string($raw) && substr($raw, 0, 3) === "\xEF\xBB\xBF") { file_put_contents($tmp, substr($raw, 3)); } $first_line = ''; if ($peek = fopen($tmp, 'r')) { $first_line = (string) fgets($peek); fclose($peek); } $delim = ','; if ($first_line !== '') { $commas = substr_count($first_line, ','); $semis = substr_count($first_line, ';'); $tabs = substr_count($first_line, "\t"); if ($semis > $commas && $semis >= $tabs) { $delim = ';'; } elseif ($tabs > $commas && $tabs > $semis) { $delim = "\t"; } } $handle = fopen($tmp, 'r'); if (!$handle) { wp_send_json_error(array('message' => __('Cannot read uploaded file.', 'ai-eshop-optimizer'))); } $header = fgetcsv($handle, 0, $delim); if (!$header || !is_array($header) || count($header) < 2) { fclose($handle); wp_send_json_error(array('message' => __('CSV must have at least a sku column and one role column. (Detected separator: ', 'ai-eshop-optimizer') . ($delim === "\t" ? 'TAB' : $delim) . ')')); } $header_map = array(); foreach ($header as $idx => $col) { $clean = strtolower(trim(str_replace("\xEF\xBB\xBF", '', (string) $col))); $header_map[$clean] = $idx; } if (!isset($header_map['sku'])) { $detected = $delim === "\t" ? 'TAB' : $delim; $found = implode(', ', array_keys($header_map)); fclose($handle); wp_send_json_error(array( 'message' => sprintf( __('CSV must include a sku column. Detected separator: %1$s. Columns found in header: %2$s', 'ai-eshop-optimizer'), $detected, $found ), )); } $sku_idx = $header_map['sku']; unset($header_map['sku']); $enabled_roles = AIEO_DMM_Settings::get('enabled_roles', array()); $role_map = array(); foreach ($header_map as $name => $idx) { foreach ($enabled_roles as $role) { if (strtolower($role) === $name) { $role_map[$role] = $idx; break; } } } if (empty($role_map)) { fclose($handle); wp_send_json_error(array('message' => __('No CSV column matches an enabled role. Enable roles first.', 'ai-eshop-optimizer'))); } $rows = array(); while (($row = fgetcsv($handle, 0, $delim)) !== false) { if (!is_array($row)) { continue; } $sku = isset($row[$sku_idx]) ? trim((string) $row[$sku_idx]) : ''; if ($sku === '') { continue; } $prices = array(); foreach ($role_map as $role => $idx) { $v = isset($row[$idx]) ? (string) $row[$idx] : ''; $v = trim(str_replace(',', '.', $v)); if ($v === '' || !is_numeric($v) || (float) $v <= 0) { continue; } $prices[$role] = (float) $v; } if (!empty($prices)) { $rows[] = array('sku' => $sku, 'prices' => $prices); } } fclose($handle); if (empty($rows)) { wp_send_json_error(array('message' => __('CSV had no valid rows.', 'ai-eshop-optimizer'))); } $job_id = wp_generate_password(16, false, false); $this->create_job($job_id, 'role_pricing_import', count($rows), array( 'mode' => $mode, 'rows' => $rows, 'roles' => array_keys($role_map), )); wp_send_json_success(array( 'job_id' => $job_id, 'total' => count($rows), 'batch_size' => 100, )); } public function ajax_process_batch() { AIEO_DMM::verify_ajax_request(); $job_id = isset($_POST['job_id']) ? sanitize_text_field(wp_unslash($_POST['job_id'])) : ''; $job = $this->load_job($job_id); if (!$job || $job['type'] !== 'role_pricing_import') { wp_send_json_error(array('message' => __('Invalid job.', 'ai-eshop-optimizer'))); } $params = json_decode($job['params'], true); if (!is_array($params) || !isset($params['rows']) || !is_array($params['rows'])) { wp_send_json_error(array('message' => __('Corrupted job state.', 'ai-eshop-optimizer'))); } $mode = isset($params['mode']) && $params['mode'] === 'overwrite' ? 'overwrite' : 'merge'; $batch_size = 100; $offset = (int) $job['processed']; if ($offset === 0 && $mode === 'overwrite') { global $wpdb; $t_new = $wpdb->prefix . 'aieo_dmm_role_prices'; $t_old = $wpdb->prefix . 'om_role_based_pricing'; $wpdb->query("TRUNCATE TABLE {$t_new}"); if (aieo_dmm_table_exists($t_old)) { $wpdb->query("TRUNCATE TABLE {$t_old}"); } self::bump_role_prices_version(); } $slice = array_slice($params['rows'], $offset, $batch_size); $errors = array(); $written = 0; foreach ($slice as $row) { $result = $this->write_row($row['sku'], $row['prices']); if ($result['ok']) { $written++; } else { $errors[] = $result['error']; } } $new_processed = $offset + count($slice); $complete = $new_processed >= (int) $job['total']; $this->update_job($job_id, array( 'processed' => $new_processed, 'status' => $complete ? 'complete' : 'running', )); if ($complete) { AIEO_DMM_Cache::bump_version('prices'); self::bump_role_prices_version(); } wp_send_json_success(array( 'processed' => $new_processed, 'total' => (int) $job['total'], 'written' => $written, 'errors' => array_slice($errors, 0, 20), 'complete' => $complete, 'percentage' => (int) $job['total'] > 0 ? (int) floor(($new_processed / (int) $job['total']) * 100) : 100, )); } private function write_row($sku, array $prices) { global $wpdb; $product_id = function_exists('wc_get_product_id_by_sku') ? (int) wc_get_product_id_by_sku($sku) : 0; if ($product_id <= 0) { return array('ok' => false, 'error' => sprintf( __('SKU %s not found.', 'ai-eshop-optimizer'), $sku )); } $parent_id = $product_id; $type = 'simple'; $post = get_post($product_id); if ($post && $post->post_type === 'product_variation') { $parent_id = (int) $post->post_parent; $type = 'variation'; } $row_base = array( 'parent_id' => $parent_id, 'product_type' => $type, 'sku' => (string) $sku, ); $row_formats = array('%d', '%s', '%s'); foreach ($prices as $role => $price) { $col = aieo_dmm_sanitize_role_column((string) $role); $row_base[$col] = (float) $price; $row_formats[] = '%f'; } $tables = array( $wpdb->prefix . 'aieo_dmm_role_prices', $wpdb->prefix . 'om_role_based_pricing', ); foreach ($tables as $table) { if (!aieo_dmm_table_exists($table)) { continue; } $exists = $wpdb->get_var($wpdb->prepare( "SELECT 1 FROM {$table} WHERE product_id = %d LIMIT 1", $product_id )); if ($exists) { $wpdb->update($table, $row_base, array('product_id' => $product_id), $row_formats, array('%d')); } else { $row_with_pk = array('product_id' => $product_id) + $row_base; $formats_with_pk = array_merge(array('%d'), $row_formats); $wpdb->insert($table, $row_with_pk, $formats_with_pk); } } return array('ok' => true); } public function ajax_export_csv() { AIEO_DMM::verify_ajax_request(); global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_role_prices'; if (!aieo_dmm_table_exists($table)) { wp_send_json_error(array('message' => __('No role pricing data yet.', 'ai-eshop-optimizer'))); } $enabled_roles = AIEO_DMM_Settings::get('enabled_roles', array()); if (empty($enabled_roles)) { wp_send_json_error(array('message' => __('Enable at least one role first.', 'ai-eshop-optimizer'))); } $cols = array('sku'); foreach ($enabled_roles as $role) { $cols[] = $role; } $db_cols = array('sku'); foreach ($enabled_roles as $role) { $db_cols[] = aieo_dmm_sanitize_role_column($role); } $select = implode(', ', array_map(function ($c) { return '`' . $c . '`'; }, $db_cols)); $rows = $wpdb->get_results("SELECT {$select} FROM {$table} ORDER BY product_id ASC", ARRAY_N); $dir = AIEO_DMM::get_upload_path('exports'); $filename = 'role-prices-' . gmdate('Ymd-His') . '.csv'; $path = trailingslashit($dir['path']) . $filename; $url = trailingslashit($dir['url']) . $filename; $handle = fopen($path, 'w'); if (!$handle) { wp_send_json_error(array('message' => __('Cannot write export file.', 'ai-eshop-optimizer'))); } fputcsv($handle, $cols); foreach ((array) $rows as $row) { fputcsv($handle, $row); } fclose($handle); wp_send_json_success(array( 'url' => $url, 'filename' => $filename, 'rows' => is_array($rows) ? count($rows) : 0, )); } public function ajax_download_template() { AIEO_DMM::verify_ajax_request(); $roles = AIEO_DMM_Settings::get('enabled_roles', array()); $cols = array_merge(array('sku'), $roles); $samples = $this->build_template_sample_rows($roles, 3); $dir = AIEO_DMM::get_upload_path('exports'); $filename = 'role-prices-template.csv'; $path = trailingslashit($dir['path']) . $filename; $url = trailingslashit($dir['url']) . $filename; $handle = fopen($path, 'w'); if (!$handle) { wp_send_json_error(array('message' => __('Cannot write template file.', 'ai-eshop-optimizer'))); } AIEO_DMM_Sample::write_csv_bom($handle); fputcsv($handle, $cols); foreach ($samples as $row) { fputcsv($handle, $row); } fclose($handle); wp_send_json_success(array('url' => $url, 'filename' => $filename)); } private function build_template_sample_rows(array $roles, $count = 3) { $rows = array(); $product_skus = array(); if (function_exists('wc_get_products')) { $products = wc_get_products(array( 'status' => 'publish', 'limit' => max(1, (int) $count), 'orderby' => 'date', 'order' => 'DESC', )); foreach ($products as $p) { $sku = (string) $p->get_sku(); if ($sku !== '') { $product_skus[] = $sku; } if (count($product_skus) >= (int) $count) { break; } } } if (empty($product_skus)) { $product_skus = array('EXAMPLE-SKU-1', 'EXAMPLE-SKU-2', 'EXAMPLE-SKU-3'); } $base_prices = array(19.99, 24.50, 9.90); foreach ($product_skus as $idx => $sku) { $row = array($sku); $base = isset($base_prices[$idx]) ? $base_prices[$idx] : 9.99; foreach ($roles as $n => $role) { $price = max(0.01, $base - ($n * 1.5)); $row[] = number_format($price, 2, '.', ''); } $rows[] = $row; if (count($rows) >= (int) $count) { break; } } return $rows; } private function count_price_rows() { global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_role_prices'; if (!aieo_dmm_table_exists($table)) { return 0; } return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table}"); } private function priced_rows_where_clause() { $roles = (array) AIEO_DMM_Settings::get('enabled_roles', array()); if (empty($roles)) { return '1=0'; } $parts = array(); foreach ($roles as $role) { $col = aieo_dmm_sanitize_role_column($role); $parts[] = "(`{$col}` IS NOT NULL AND `{$col}` > 0)"; } return '(' . implode(' OR ', $parts) . ')'; } private function count_priced_rows() { global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_role_prices'; if (!aieo_dmm_table_exists($table)) { return 0; } $where = $this->priced_rows_where_clause(); return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table} WHERE {$where}"); } private function fetch_priced_rows($per_page, $page) { global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_role_prices'; if (!aieo_dmm_table_exists($table)) { return array(); } $where = $this->priced_rows_where_clause(); $offset = max(0, ((int) $page - 1) * (int) $per_page); $sql = $wpdb->prepare( "SELECT * FROM {$table} WHERE {$where} ORDER BY product_id ASC LIMIT %d OFFSET %d", (int) $per_page, $offset ); $rows = $wpdb->get_results($sql, ARRAY_A); return is_array($rows) ? $rows : array(); } private function fetch_price_rows($per_page, $page) { global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_role_prices'; if (!aieo_dmm_table_exists($table)) { return array(); } $offset = max(0, ((int) $page - 1) * (int) $per_page); $sql = $wpdb->prepare( "SELECT * FROM {$table} ORDER BY product_id ASC LIMIT %d OFFSET %d", (int) $per_page, $offset ); $rows = $wpdb->get_results($sql, ARRAY_A); return is_array($rows) ? $rows : array(); } private function create_job($job_id, $type, $total, array $params) { global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_export_jobs'; if (!aieo_dmm_table_exists($table)) { return; } $wpdb->insert($table, array( 'job_id' => $job_id, 'type' => $type, 'status' => 'running', 'total' => $total, 'processed' => 0, 'params' => wp_json_encode($params), 'user_id' => get_current_user_id(), ), array('%s', '%s', '%s', '%d', '%d', '%s', '%d')); } private function load_job($job_id) { global $wpdb; if ($job_id === '') { return null; } $table = $wpdb->prefix . 'aieo_dmm_export_jobs'; $row = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$table} WHERE job_id = %s", $job_id ), ARRAY_A); return is_array($row) ? $row : null; } private function update_job($job_id, array $fields) { global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_export_jobs'; $formats = array(); foreach ($fields as $k => $v) { $formats[] = in_array($k, array('processed', 'total', 'last_id', 'user_id'), true) ? '%d' : '%s'; } $wpdb->update($table, $fields, array('job_id' => $job_id), $formats, array('%s')); } public function ajax_gf_export_forms() { AIEO_DMM::verify_ajax_request(); if (!class_exists('GFAPI') || !class_exists('GFExport')) { wp_send_json_error(array('message' => __('Gravity Forms is not active on this site.', 'ai-eshop-optimizer'))); } $ids = array(); foreach (array('gf_registration_form_id', 'gf_update_form_id', 'gf_prompt_form_id') as $k) { $id = (int) AIEO_DMM_Settings::get($k, 0); if ($id > 0) { $ids[$id] = true; } } $ids = array_keys($ids); if (empty($ids)) { wp_send_json_error(array('message' => __('Configure at least one form ID first.', 'ai-eshop-optimizer'))); } $forms = array(); foreach ($ids as $id) { $form = GFAPI::get_form((int) $id); if (is_array($form)) { $forms[] = $form; } } if (empty($forms)) { wp_send_json_error(array('message' => __('Could not resolve any of the configured forms.', 'ai-eshop-optimizer'))); } $payload = array(); $payload['version'] = defined('GFForms::$version') ? GFForms::$version : '2.7'; $payload['aieo_export_meta'] = array( 'exported_at' => gmdate('c'), 'gf_registration_form_id' => (int) AIEO_DMM_Settings::get('gf_registration_form_id', 0), 'gf_update_form_id' => (int) AIEO_DMM_Settings::get('gf_update_form_id', 0), 'gf_prompt_form_id' => (int) AIEO_DMM_Settings::get('gf_prompt_form_id', 0), 'gf_checkbox_field_id' => (int) AIEO_DMM_Settings::get('gf_checkbox_field_id', 11), 'gf_role_map' => (array) AIEO_DMM_Settings::get('gf_role_map', array()), ); foreach ($forms as $i => $form) { $payload[(string) $i] = $form; } $dir = AIEO_DMM::get_upload_path('exports'); $filename = 'gf-membership-forms-' . gmdate('Ymd-His') . '.json'; $path = trailingslashit($dir['path']) . $filename; $url = trailingslashit($dir['url']) . $filename; $written = file_put_contents($path, wp_json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); if ($written === false) { wp_send_json_error(array('message' => __('Could not write export file.', 'ai-eshop-optimizer'))); } wp_send_json_success(array( 'url' => $url, 'filename' => $filename, 'forms' => count($forms), )); } private function gf_inverted_role_map() { $map = (array) AIEO_DMM_Settings::get('gf_role_map', array()); $out = array(); foreach ($map as $slug => $value) { $int_val = (int) $value; if ($int_val > 0 && (string) $slug !== '') { $out[$int_val] = (string) $slug; } } return $out; } private function gf_collected_checkbox_values($entry) { $field_id = (int) AIEO_DMM_Settings::get('gf_checkbox_field_id', 11); if ($field_id <= 0 || !is_array($entry)) { return array(); } $out = array(); for ($i = 1; $i <= 30; $i++) { $key = $field_id . '.' . $i; if (!isset($entry[$key])) { continue; } $raw = trim((string) $entry[$key]); if ($raw === '') { continue; } $iv = (int) $raw; if ($iv > 0) { $out[] = $iv; } } return $out; } public function gf_assign_roles_on_registration($user_id, $user_config, $entry) { $form_id = (int) AIEO_DMM_Settings::get('gf_registration_form_id', 0); if ($form_id <= 0) { return; } if (!is_array($entry) || (int) (isset($entry['form_id']) ? $entry['form_id'] : 0) !== $form_id) { return; } $user = get_userdata($user_id); if (!$user) { return; } $inv = $this->gf_inverted_role_map(); if (empty($inv)) { return; } foreach ($this->gf_collected_checkbox_values($entry) as $val) { if (isset($inv[$val])) { AIEO_Safe_Roles::grant((int) $user_id, $inv[$val], 'gravity_forms'); } } } public function gf_modify_roles_on_update($entry, $form) { $form_id = (int) AIEO_DMM_Settings::get('gf_update_form_id', 0); if ($form_id <= 0) { return; } if (!is_array($form) || (int) $form['id'] !== $form_id) { return; } $user = wp_get_current_user(); if (!$user || !$user->ID) { return; } $inv = $this->gf_inverted_role_map(); if (empty($inv)) { return; } $chosen = array(); foreach ($this->gf_collected_checkbox_values($entry) as $val) { if (isset($inv[$val])) { $chosen[] = $inv[$val]; AIEO_Safe_Roles::grant((int) $user->ID, $inv[$val], 'gravity_forms'); } } foreach ($inv as $existing_role) { if (!in_array($existing_role, $chosen, true)) { AIEO_Safe_Roles::revoke((int) $user->ID, $existing_role, 'gravity_forms'); } } delete_transient('aieo_pre_gf_roles_' . $user->ID); } public function gf_emit_program_prompt($entry, $form) { $form_id = (int) AIEO_DMM_Settings::get('gf_prompt_form_id', 0); if ($form_id <= 0) { return; } if (!is_array($form) || (int) $form['id'] !== $form_id) { return; } $pro_field = (int) AIEO_DMM_Settings::get('gf_prompt_pro_field_id', 51); $member_field = (int) AIEO_DMM_Settings::get('gf_prompt_member_field_id', 48); $page_id = (int) AIEO_DMM_Settings::get('gf_professionals_page_id', 0); if ($page_id <= 0) { return; } $is_pro = (string) (isset($entry[$pro_field]) ? $entry[$pro_field] : '') === '1'; $not_in_prog = empty($entry[$member_field]) || (string) $entry[$member_field] === '0'; if (!$is_pro || !$not_in_prog) { return; } $url = get_permalink($page_id); if (!$url) { return; } echo "

" . esc_html__('You\'re a professional but not yet enrolled in the program — ', 'ai-eshop-optimizer') . '' . esc_html__('join here', 'ai-eshop-optimizer') . '

'; } public function gf_capture_pre_submission_roles() { if (!is_user_logged_in()) { return; } $page_id = (int) AIEO_DMM_Settings::get('gf_professionals_page_id', 0); if ($page_id <= 0 || !is_page($page_id)) { return; } $user = wp_get_current_user(); if (!$user || !$user->ID) { return; } set_transient('aieo_pre_gf_roles_' . $user->ID, (array) $user->roles, 20000); } public function gf_print_post_login_refresh() { $page_id = (int) AIEO_DMM_Settings::get('gf_professionals_page_id', 0); if ($page_id <= 0 || !is_page($page_id)) { return; } if (!isset($_GET['just_logged_in'])) { return; } ?> post_name) || $page->post_name === '') { return; } $uri = isset($_SERVER['REQUEST_URI']) ? (string) sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; if ($uri === '' || strpos($uri, '/' . $page->post_name) === false) { return; } header('Cache-Control: no-cache, must-revalidate, max-age=0'); header('Pragma: no-cache'); header('Expires: Wed, 11 Jan 1984 05:00:00 GMT'); } public function gf_membership_shortcode() { if (class_exists('AIEO_Pro_Signup') && 'aieo' === AIEO_Pro_Signup::provider()) { return AIEO_Pro_Signup::render('professional'); } if (!function_exists('gravity_form')) { return ''; } $reg_form_id = (int) AIEO_DMM_Settings::get('gf_registration_form_id', 0); $update_form_id = (int) AIEO_DMM_Settings::get('gf_update_form_id', 0); if ($reg_form_id <= 0 && $update_form_id <= 0) { return ''; } if (is_user_logged_in()) { if ($update_form_id <= 0) { return ''; } $user = wp_get_current_user(); $map = (array) AIEO_DMM_Settings::get('gf_role_map', array()); $values = array(); foreach ((array) $user->roles as $role) { if (isset($map[$role]) && (int) $map[$role] > 0) { $values[] = (int) $map[$role]; } } $intro = (string) AIEO_DMM_Settings::get('gf_intro_logged_in', ''); $name = trim($user->first_name . ' ' . $user->last_name); if ($name === '') { $name = $user->display_name; } $intro = str_replace( array('{user_name}', '{first_name}', '{last_name}'), array(esc_html($name), esc_html($user->first_name), esc_html($user->last_name)), $intro ); ob_start(); if ($intro !== '') { echo '
' . wp_kses_post($intro) . '
'; } echo gravity_form((int) $update_form_id, false, true, false, array( 'customer_email' => $user->user_email, 'user_id' => $user->ID, 'first_name' => $user->first_name, 'last_name' => $user->last_name, 'user_name' => $user->user_login, 'nick_name' => $user->nickname, 'membership' => implode(',', $values), ), true, 1, false); return ob_get_clean(); } if ($reg_form_id <= 0) { } $intro = (string) AIEO_DMM_Settings::get('gf_intro_logged_out', ''); $page_id = (int) AIEO_DMM_Settings::get('gf_professionals_page_id', 0); $return_url = $page_id > 0 ? get_permalink($page_id) : home_url(); if ($return_url) { $return_url = add_query_arg(array( 'just_logged_in' => 'true', 'ts' => time(), ), $return_url); } $intro = str_replace('{return_url}', esc_url($return_url), $intro); ob_start(); if ($intro !== '') { echo '
' . wp_kses_post($intro) . '
'; } if ($reg_form_id > 0) { echo gravity_form((int) $reg_form_id, false, true, false, null, true, 1, false); } return ob_get_clean(); } }