| @@ -33,9 +33,11 @@ | ||
| 33 | 33 | public function __construct(?int $user_id = null, ?string $session_key = null) |
| 34 | 34 | { |
| 35 | 35 | $this->session = new Wishlist_Session(); |
| 36 | 36 | $this->user_id = $user_id ?? get_current_user_id(); |
| 37 | - $this->session_key = $session_key ?: $this->session->get_session_key(); | |
| 37 | + $this->session_key = ($session_key !== null && $session_key !== '') | |
| 38 | + ? $session_key | |
| 39 | + : $this->session->get_session_key(false); | |
| 38 | 40 | $this->active_wishlist_id = $this->resolve_active_wishlist_id(); |
| 39 | 41 | } |
| 40 | 42 | |
| 41 | 43 | /** |
| @@ -72,8 +74,10 @@ | ||
| 72 | 74 | * @return array|WP_Error Operation result. |
| 73 | 75 | */ |
| 74 | 76 | public function add_item(int $product_id, int $variation_id = 0, int $qty = 1, ?string $wishlist_id = null) |
| 75 | 77 | { |
| 78 | + $this->ensure_guest_session(); | |
| 79 | + | |
| 76 | 80 | $validation = $this->validate_product($product_id, $variation_id); |
| 77 | 81 | if (is_wp_error($validation)) { |
| 78 | 82 | return $validation; |
| 79 | 83 | } |
| @@ -193,8 +197,12 @@ | ||
| 193 | 197 | * @return array<int, object> List of wishlist rows. |
| 194 | 198 | */ |
| 195 | 199 | public function get_items(?string $wishlist_id = null): array |
| 196 | 200 | { |
| 201 | + if ($this->is_anonymous_guest()) { | |
| 202 | + return []; | |
| 203 | + } | |
| 204 | + | |
| 197 | 205 | $wishlist_id = $this->normalize_wishlist_id($wishlist_id); |
| 198 | 206 | global $wpdb; |
| 199 | 207 | |
| 200 | 208 | $where = $this->get_scope_where($wishlist_id); |
| @@ -227,8 +235,12 @@ | ||
| 227 | 235 | * @return array<int, object> Lists rows. |
| 228 | 236 | */ |
| 229 | 237 | public function get_lists(): array |
| 230 | 238 | { |
| 239 | + if ($this->is_anonymous_guest()) { | |
| 240 | + return []; | |
| 241 | + } | |
| 242 | + | |
| 231 | 243 | global $wpdb; |
| 232 | 244 | |
| 233 | 245 | $lists_table = Wishlist_DB::get_lists_table(); |
| 234 | 246 | $where = $this->user_id > 0 |
| @@ -261,8 +273,10 @@ | ||
| 261 | 273 | * @return array<string, mixed>|WP_Error Created list data or error. |
| 262 | 274 | */ |
| 263 | 275 | public function create_list(string $title, string $visibility = 'private') |
| 264 | 276 | { |
| 277 | + $this->ensure_guest_session(); | |
| 278 | + | |
| 265 | 279 | global $wpdb; |
| 266 | 280 | |
| 267 | 281 | if (empty($title)) { |
| 268 | 282 | return new WP_Error('wishlist_title_missing', esc_html__('List title is required.', 'king-addons')); |
| @@ -477,8 +491,12 @@ | ||
| 477 | 491 | * @return int Count of items. |
| 478 | 492 | */ |
| 479 | 493 | public function get_count(?string $wishlist_id = null, bool $force_refresh = false): int |
| 480 | 494 | { |
| 495 | + if ($this->is_anonymous_guest()) { | |
| 496 | + return 0; | |
| 497 | + } | |
| 498 | + | |
| 481 | 499 | $wishlist_id = $this->normalize_wishlist_id($wishlist_id); |
| 482 | 500 | $cache_key = $this->get_cache_key($wishlist_id); |
| 483 | 501 | $cache_enabled = Wishlist_Settings::get('cache_enabled', false); |
| 484 | 502 | $cache_ttl = max(0, intval(Wishlist_Settings::get('cache_ttl', self::CACHE_TTL))); |
| @@ -613,8 +631,15 @@ | ||
| 613 | 631 | * @return void |
| 614 | 632 | */ |
| 615 | 633 | public function ensure_default_list(string $wishlist_id): void |
| 616 | 634 | { |
| 635 | + if ($this->user_id <= 0) { | |
| 636 | + $this->ensure_guest_session(); | |
| 637 | + if ($this->session_key === '') { | |
| 638 | + return; | |
| 639 | + } | |
| 640 | + } | |
| 641 | + | |
| 617 | 642 | global $wpdb; |
| 618 | 643 | |
| 619 | 644 | $lists_table = Wishlist_DB::get_lists_table(); |
| 620 | 645 | |
| @@ -664,8 +689,12 @@ | ||
| 664 | 689 | * @return object|null Wishlist row. |
| 665 | 690 | */ |
| 666 | 691 | private function get_item_row(string $wishlist_id, int $product_id, int $variation_id): ?object |
| 667 | 692 | { |
| 693 | + if ($this->is_anonymous_guest()) { | |
| 694 | + return null; | |
| 695 | + } | |
| 696 | + | |
| 668 | 697 | global $wpdb; |
| 669 | 698 | $table = Wishlist_DB::get_items_table(); |
| 670 | 699 | $where = $this->get_scope_where($wishlist_id); |
| 671 | 700 | $where['sql'] .= ' AND product_id = %d AND variation_id = %d'; |
| @@ -695,8 +724,32 @@ | ||
| 695 | 724 | return new WP_Error('wishlist_invalid_product', esc_html__('Product not found.', 'king-addons')); |
| 696 | 725 | } |
| 697 | 726 | |
| 698 | 727 | return true; |
| 728 | + } | |
| 729 | + | |
| 730 | + /** | |
| 731 | + * Whether this request is a guest with no session cookie yet. | |
| 732 | + * | |
| 733 | + * @return bool True when reads should stay empty and skip Set-Cookie. | |
| 734 | + */ | |
| 735 | + private function is_anonymous_guest(): bool | |
| 736 | + { | |
| 737 | + return $this->user_id <= 0 && $this->session_key === ''; | |
| 738 | + } | |
| 739 | + | |
| 740 | + /** | |
| 741 | + * Mint a guest cookie only when a write actually needs identity. | |
| 742 | + * | |
| 743 | + * @return void | |
| 744 | + */ | |
| 745 | + private function ensure_guest_session(): void | |
| 746 | + { | |
| 747 | + if ($this->user_id > 0 || $this->session_key !== '') { | |
| 748 | + return; | |
| 749 | + } | |
| 750 | + | |
| 751 | + $this->session_key = $this->session->get_session_key(true); | |
| 699 | 752 | } |
| 700 | 753 | |
| 701 | 754 | /** |
| 702 | 755 | * Build scope-aware WHERE clause for queries. |