roleManager = new RoleManager(); } public function execute(Operation $operation, Progress $progress): Result { error_log('Executing Content Term.... '); // Extract taxonomy from operation type (e.g., "shop_update" -> "shop") $data= $operation->requestData; $taxonomy = $data['taxonomy']??false; $registrar = $taxonomy? Registrar::getInstance($taxonomy) : false; if (!$taxonomy || !$registrar) { return Result::fail("Invalid taxonomy: {$taxonomy}"); } return match(true) { str_ends_with($operation->type, '_update') => $this->processUpdate($operation, $taxonomy), str_ends_with($operation->type, '_member_add') => $this->processMemberAdd($operation, $taxonomy), str_ends_with($operation->type, '_member_remove') => $this->processMemberRemove($operation, $taxonomy), default => Result::fail("Unknown operation type: {$operation->type}") }; } /** * Process term metadata updates */ protected function processUpdate(Operation $operation, string $taxonomy): Result { $termID = $operation->requestData['term_id'] ?? 0; $userID = $operation->userId; if (!$termID || !term_exists($termID, jvbCheckBase($taxonomy))) { return Result::fail('Invalid term ID'); } // Verify permissions using RoleManager if (!user_can($userID, 'manage_options') && !$this->roleManager->isManager($userID, $termID)) { return Result::fail('User does not have permission to manage this ' . $taxonomy); } try { $meta = Meta::forTerm($termID); $data = $operation->requestData; unset($data['term_id']); // Filter to only allowed fields $allowed = Registrar::getFieldsFor($taxonomy); $setData = array_filter( $data, fn($key) => array_key_exists($key, $allowed), ARRAY_FILTER_USE_KEY ); if (empty($setData)) { return Result::fail('No valid fields to update'); } // Update metadata $results = $meta->setAll($setData); if ($results) { return Result::success([ 'updated_fields' => array_keys($setData), 'term_id' => $termID ]); } return Result::fail('Failed to update term metadata'); } catch (Exception $e) { return Result::fail('Update error: ' . $e->getMessage()); } } /** * Add member to term (via history table) */ protected function processMemberAdd(Operation $operation, string $taxonomy): Result { $termID = $operation->requestData['term_id'] ?? 0; $targetUserID = $operation->requestData['target_user'] ?? 0; $userID = $operation->userId; if (!$termID || !term_exists($termID, jvbCheckBase($taxonomy))) { return Result::fail('Invalid term ID'); } if (!get_userdata($targetUserID)) { return Result::fail('Invalid target user'); } // Verify permissions if (!user_can($userID, 'manage_options') && !$this->roleManager->isManager($userID, $termID)) { return Result::fail('User does not have permission to manage this ' . $taxonomy); } // Check if tracking enabled $registrar = Registrar::getInstance($taxonomy); if ($registrar && !$registrar->hasFeature('track_changes')) { return Result::fail('Member tracking not enabled for ' . $taxonomy); } try { return $this->addMember($targetUserID, $termID, $taxonomy); } catch (Exception $e) { return Result::fail('Add member error: ' . $e->getMessage()); } } /** * Remove member from term (via history table) */ protected function processMemberRemove(Operation $operation, string $taxonomy): Result { $termID = $operation->requestData['term_id'] ?? 0; $targetUserID = $operation->requestData['target_user'] ?? 0; $userID = $operation->userId; if (!$termID || !term_exists($termID, jvbCheckBase($taxonomy))) { return Result::fail('Invalid term ID'); } if (!get_userdata($targetUserID)) { return Result::fail('Invalid target user'); } // Verify permissions if (!user_can($userID, 'manage_options') && !$this->roleManager->isManager($userID, $termID)) { return Result::fail('User does not have permission to manage this ' . $taxonomy); } try { return $this->removeMember($targetUserID, $termID, $taxonomy); } catch (Exception $e) { return Result::fail('Remove member error: ' . $e->getMessage()); } } /** * Add member to term with transaction support */ protected function addMember(int $userID, int $termID, string $taxonomy): Result { $registrar = Registrar::getInstance($taxonomy); if (!$registrar) { return Result::fail('No content registered'); } $forContent = $registrar->registrar->for; if (empty($forContent)) { return Result::fail('No content types configured for ' . $taxonomy); } // Get table name (e.g., "history_artist_shop") $contentType = is_array($forContent) ? $forContent[0] : $forContent; // Use first content type $tableName = "history_{$contentType}_{$taxonomy}"; $table = CustomTable::for($tableName); return $table->transaction(function($table) use ($userID, $termID, $taxonomy, $contentType) { // Check if already a member $existing = $table ->where([ 'user_id' => $userID, 'term_id' => $termID, 'end_date' => null ]) ->first(); if ($existing) { return Result::success([ 'message' => 'User is already a member', 'existing' => true ]); } // Get user's content post ID $contentID = get_user_meta($userID, BASE . 'link', true); if (!$contentID) { throw new Exception('User profile not found'); } // Verify content post exists $post = get_post($contentID); if (!$post || $post->post_type !== BASE . $contentType) { throw new Exception('Content post not found or invalid type'); } // Insert new membership $result = $table->create([ 'user_id' => $userID, 'content_id' => $contentID, 'term_id' => $termID, 'role' => 'member', 'is_primary' => 1, 'start_date' => current_time('mysql') ]); if (!$result) { throw new Exception('Failed to create membership record'); } // Add taxonomy term to content post $termResult = wp_set_object_terms($contentID, [$termID], jvbCheckBase($taxonomy), true); if (is_wp_error($termResult)) { throw new Exception('Failed to set taxonomy term: ' . $termResult->get_error_message()); } // Notify term managers $this->notifyTermManagers($termID, $userID, $taxonomy, 'member_added'); return Result::success([ 'message' => 'Member added successfully', 'user_id' => $userID, 'term_id' => $termID ]); }); } /** * Remove member from term with transaction support */ protected function removeMember(int $userID, int $termID, string $taxonomy): Result { $registrar = Registrar::getInstance($taxonomy); if (!$registrar) { return Result::fail('No content registered'); } $forContent = $registrar->registrar->for; if (empty($forContent)) { return Result::fail('No content types configured for ' . $taxonomy); } // Get table name $contentType = is_array($forContent) ? $forContent[0] : $forContent; $tableName = "history_{$contentType}_{$taxonomy}"; $table = CustomTable::for($tableName); return $table->transaction(function($table) use ($userID, $termID, $taxonomy, $contentType) { // Get user's content post ID $contentID = get_user_meta($userID, BASE . 'link', true); if (!$contentID) { throw new Exception('User profile not found'); } // Update membership record - set end_date $updated = $table ->where([ 'user_id' => $userID, 'term_id' => $termID, 'end_date' => null ]) ->updateResults([ 'end_date' => current_time('mysql'), 'is_primary' => 0 ]); if (!$updated) { throw new Exception('No active membership found'); } // Remove taxonomy term from content post $termResult = wp_remove_object_terms($contentID, [$termID], jvbCheckBase($taxonomy)); if (is_wp_error($termResult)) { throw new Exception('Failed to remove taxonomy term: ' . $termResult->get_error_message()); } // Notify term managers $this->notifyTermManagers($termID, $userID, $taxonomy, 'member_removed'); return Result::success([ 'message' => 'Member removed successfully', 'user_id' => $userID, 'term_id' => $termID ]); }); } /** * Notify term owners/managers about member changes */ protected function notifyTermManagers(int $termID, int $userID, string $taxonomy, string $notificationType): void { $managers = $this->roleManager->getManagedTerms($userID, $taxonomy); $term = get_term($termID, jvbCheckBase($taxonomy)); $user = get_userdata($userID); foreach ($managers as $managerID) { JVB()->notification()->addNotification( $managerID, $notificationType, [ 'user_id' => $userID, 'user_name' => $user ? $user->display_name : 'Unknown', 'term_id' => $termID, 'term_name' => $term && !is_wp_error($term) ? $term->name : 'Unknown', 'taxonomy' => $taxonomy ] ); } } }