| | |
| | | <?php |
| | | namespace JVBase\managers; |
| | | |
| | | use JVBase\JVB; |
| | | use JVBase\managers\CacheManager; |
| | | use WP_Post; |
| | | use WP_Error; |
| | | use Exception; |
| | |
| | | class UserTermsManager |
| | | { |
| | | private string $table_name; |
| | | private CacheManager $cache; |
| | | private Cache $cache; |
| | | private string $cacheGroup = 'user_terms_'; |
| | | private int $ttl = DAY_IN_SECONDS; // 1 day default |
| | | protected \wpdb $wpdb; |
| | |
| | | global $wpdb; |
| | | $this->wpdb = $wpdb; |
| | | $this->table_name = $this->wpdb->prefix . BASE . 'user_term_index'; |
| | | // Get cache manager instance |
| | | $this->cache = new CacheManager($this->cacheGroup, $this->ttl); |
| | | |
| | | // Register hooks |
| | | add_action('save_post', [$this, 'updatePostUserTerms'], 10, 3); |
| | |
| | | */ |
| | | public function clearUserCache(int $user_id, string|null $taxonomy = null):void |
| | | { |
| | | if ($taxonomy) { |
| | | // Clear specific taxonomy cache |
| | | $pattern = "user_{$user_id}_" . str_replace(BASE, '', $taxonomy); |
| | | $this->cache->clearPattern($pattern); |
| | | } else { |
| | | // Clear all user term caches |
| | | $pattern = "user_{$user_id}_"; |
| | | $this->cache->clearPattern($pattern); |
| | | } |
| | | $cache = Cache::for($user_id.'_term_relationships', DAY_IN_SECONDS)->connect('post', true)->connect('taxonomy', true); |
| | | $cache->flush(); |
| | | } |
| | | |
| | | // Update term usage when a post is saved |
| | |
| | | if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) { |
| | | return; |
| | | } |
| | | // SAFETY: Skip attachments and other non-content post types |
| | | if (in_array($post->post_type, jvbIgnoredPostTypes())) { |
| | | return; |
| | | } |
| | | |
| | | // Skip non-custom post types |
| | | $post_type = get_post_type($post); |
| | |
| | | $this->wpdb->query("TRUNCATE TABLE {$this->table_name}"); |
| | | |
| | | // Get all users with posts |
| | | $users = $this->wpdb->get_col(" |
| | | SELECT DISTINCT post_author |
| | | FROM {$this->wpdb->posts} |
| | | WHERE post_status = 'publish' |
| | | AND post_type LIKE '" . BASE . "%' |
| | | "); |
| | | $users = $this->wpdb->get_col($this->wpdb->prepare( |
| | | "SELECT DISTINCT post_author |
| | | FROM {$this->wpdb->posts} |
| | | WHERE post_status = 'publish' |
| | | AND post_type LIKE %s", |
| | | $this->wpdb->esc_like(BASE) . '%' |
| | | )); |
| | | |
| | | JVB()->queue()->queueOperation( |
| | | 'rebuild_user_term_index', |
| | |
| | | $this->clearUserCache($user_id); |
| | | |
| | | // Get all the user's published posts |
| | | $posts = $this->wpdb->get_col($this->wpdb->prepare( |
| | | "SELECT ID FROM {$this->wpdb->posts} |
| | | WHERE post_author = %d |
| | | AND post_status = 'publish' |
| | | AND post_type LIKE '%s'", |
| | | $user_id, |
| | | BASE |
| | | )); |
| | | $posts = $this->wpdb->get_col($this->wpdb->prepare( |
| | | "SELECT ID FROM {$this->wpdb->posts} |
| | | WHERE post_author = %d |
| | | AND post_status = 'publish' |
| | | AND post_type LIKE %s", |
| | | $user_id, |
| | | $this->wpdb->esc_like(BASE) . '%' |
| | | )); |
| | | |
| | | $processed_terms = 0; |
| | | |
| | |
| | | private function fetchUserTerms(int $user_id, string $taxonomy, array $args):array |
| | | { |
| | | $taxonomy = jvbCheckBase($taxonomy); |
| | | $key = $this->cache->generateKey(array_merge( |
| | | $cache = Cache::for($user_id.'_term_relationships', DAY_IN_SECONDS)->connect('post', true)->connect('taxonomy', true); |
| | | $key = $cache->generateKey(array_merge( |
| | | [ |
| | | 'user' => $user_id, |
| | | 'taxonomy' => $taxonomy, |
| | | ], |
| | | $args |
| | | )); |
| | | if (!$args['skip_cache']) { |
| | | $cache = $this->cache->get($key); |
| | | if ($cache) { |
| | | return $cache; |
| | | $cached = $cache->get($key); |
| | | if ($cached) { |
| | | return $cached; |
| | | } |
| | | } |
| | | |
| | |
| | | $this->wpdb->prepare($query, $query_args), |
| | | ARRAY_A |
| | | ); |
| | | $this->cache->set($key, $results); |
| | | $cache->set($key, $results); |
| | | |
| | | return $results; |
| | | } |
| | |
| | | }, $terms); |
| | | } |
| | | |
| | | /** |
| | | * @param int $user_id |
| | | * |
| | | * @return bool |
| | | */ |
| | | public function warmCache(int $user_id):bool |
| | | { |
| | | // Get all taxonomies |
| | | $taxonomies = getTaxonomies(['_builtin' => false], 'names'); |
| | | |
| | | foreach ($taxonomies as $taxonomy) { |
| | | if (str_starts_with($taxonomy, BASE)) { |
| | | // Pre-cache the most common queries |
| | | $common_args = [ |
| | | // Most frequently used terms |
| | | [ |
| | | 'orderby' => 'count', |
| | | 'order' => 'DESC', |
| | | 'limit' => 20, |
| | | 'include_parents' => true |
| | | ], |
| | | // Recently used terms |
| | | [ |
| | | 'orderby' => 'last_used', |
| | | 'order' => 'DESC', |
| | | 'limit' => 20, |
| | | 'include_parents' => true |
| | | ], |
| | | // Alphabetical list |
| | | [ |
| | | 'orderby' => 'name', |
| | | 'order' => 'ASC', |
| | | 'limit' => 0, |
| | | 'include_parents' => true |
| | | ], |
| | | // Direct terms only (no parents) |
| | | [ |
| | | 'orderby' => 'count', |
| | | 'order' => 'DESC', |
| | | 'limit' => 0, |
| | | 'only_direct' => true |
| | | ] |
| | | ]; |
| | | |
| | | foreach ($common_args as $args) { |
| | | // Force skip_cache to ensure we get fresh data |
| | | $args['skip_cache'] = true; |
| | | |
| | | // Warm the cache by executing the query |
| | | $this->getUserTerms($user_id, $taxonomy, $args); |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | } |