| | |
| | | namespace JVBase\meta; |
| | | |
| | | use Exception; |
| | | use JVBase\managers\Cache; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | | exit; |
| | |
| | | return $this->getWpDefault($item, $name); |
| | | } |
| | | |
| | | // Taxonomy fields are stored in term_relationships, not meta |
| | | $config = $item->getFieldConfig($name); |
| | | if ($config |
| | | && ( |
| | | ($config['type'] ?? '') === 'taxonomy' |
| | | || (($config['type']??'') === 'selector' && ($config['subtype']??'') === 'taxonomy') |
| | | ) && !isset($config['taxonomy_type'])) { |
| | | return $this->getTaxonomyField($item, $config); |
| | | } |
| | | |
| | | $metaKey = BASE . $name; |
| | | |
| | | return match ($item->objectType) { |
| | |
| | | |
| | | $defaults = Item::WP_DEFAULTS[$item->objectType] ?? []; |
| | | $wpFields = array_intersect($defaults, $fieldNames); |
| | | $metaFields = array_diff($fieldNames, $wpFields); |
| | | |
| | | // Separate taxonomy fields from regular meta fields |
| | | $taxonomyFields = []; |
| | | $metaFields = []; |
| | | foreach (array_diff($fieldNames, $wpFields) as $name) { |
| | | $config = $item->getFieldConfig($name); |
| | | if ($config |
| | | && ( |
| | | ($config['type'] ?? '') === 'taxonomy' |
| | | || (($config['type']??'') === 'selector' && ($config['subtype']??'') === 'taxonomy') |
| | | ) && (!isset($config['taxonomy_type']) || !isset($config['isReference']))) { |
| | | $taxonomyFields[$name] = $config; |
| | | } else { |
| | | $metaFields[] = $name; |
| | | } |
| | | } |
| | | |
| | | $values = []; |
| | | |
| | | // Get meta fields in bulk query |
| | | if (!empty($metaFields)) { |
| | | $values = $this->bulkGetMeta($item, $metaFields); |
| | | } |
| | | |
| | | // Get WP default fields |
| | | foreach ($wpFields as $name) { |
| | | $values[$name] = $this->getWpDefault($item, $name); |
| | | } |
| | | |
| | | foreach ($taxonomyFields as $name => $config) { |
| | | $values[$name] = $this->getTaxonomyField($item, $config); |
| | | } |
| | | |
| | | return $values; |
| | | } |
| | | |
| | | protected function getTaxonomyField(Item $item, array $config): string |
| | | { |
| | | $taxonomy = jvbCheckBase($config['taxonomy']); |
| | | $terms = wp_get_object_terms($item->id, $taxonomy, ['fields' => 'ids']); |
| | | |
| | | if (is_wp_error($terms) || empty($terms)) { |
| | | return ''; |
| | | } |
| | | |
| | | return implode(',', $terms); |
| | | } |
| | | |
| | | /** |
| | | * Save a single field |
| | | */ |
| | |
| | | } |
| | | |
| | | if ($field->isTaxonomy()) { |
| | | error_log('Saving Taxonomy field with set_object_terms'); |
| | | return $this->saveTaxonomyField($item, $field); |
| | | } |
| | | |
| | | $metaKey = BASE . $field->name; |
| | | |
| | | return match ($item->objectType) { |
| | | 'post' => update_post_meta($item->id, $metaKey, $field->value) !== false, |
| | | 'term' => update_term_meta($item->id, $metaKey, $field->value) !== false, |
| | | 'user', 'integrations' => update_user_meta($item->id, $metaKey, $field->value) !== false, |
| | | $result = match ($item->objectType) { |
| | | 'post' => (bool)update_post_meta($item->id, $metaKey, $field->value), |
| | | 'term' => (bool)update_term_meta($item->id, $metaKey, $field->value), |
| | | 'user', 'integrations' => (bool)update_user_meta($item->id, $metaKey, $field->value), |
| | | 'options' => $this->saveOption($item, $field), |
| | | default => false |
| | | }; |
| | | |
| | | error_log('Result: '.print_r($result, true)); |
| | | return $result; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | $this->wpdb->query('START TRANSACTION'); |
| | | |
| | | try { |
| | | foreach ($dirty as $field) { |
| | | if (!$this->saveField($item, $field)) { |
| | | error_log("Could not save field: {$field->name}"); |
| | | throw new Exception("Failed to save field: {$field->name}"); |
| | | } |
| | | $field->markClean(); |
| | |
| | | $this->wpdb->query('COMMIT'); |
| | | |
| | | // Update post modified timestamp |
| | | if ($updateTimestamp && $item->objectType === 'post' && $item->id) { |
| | | wp_update_post(['ID' => $item->id]); |
| | | } |
| | | |
| | | Cache::invalidateItem($item->objectType, $item->id); |
| | | $this->clearCache($item); |
| | | |
| | | return true; |
| | |
| | | { |
| | | return match ($name) { |
| | | 'post_title' => get_the_title($item->id), |
| | | 'post_excerpt' => get_the_excerpt($item->id), |
| | | 'post_excerpt' => has_excerpt($item->id) ? get_the_excerpt($item->id):'', |
| | | 'post_content' => get_post_field('post_content', $item->id), |
| | | default => $item->wpObject->$name ?? '' |
| | | }; |
| | |
| | | protected function getTermField(Item $item, string $name): mixed |
| | | { |
| | | return match ($name) { |
| | | 'term_name' => get_term_field('name', $item->id), |
| | | 'name' => get_term_field('name', $item->id), |
| | | 'description' => get_term_field('description', $item->id), |
| | | default => '' |
| | | }; |
| | |
| | | $value = $field->value; |
| | | |
| | | if (in_array($name, ['featured_image', 'post_thumbnail'])) { |
| | | if (empty($value)) { |
| | | return delete_post_thumbnail($item->id); |
| | | } |
| | | return set_post_thumbnail($item->id, $value) !== false; |
| | | } |
| | | |
| | | // Special handling for post_status (trash/delete require specific functions) |
| | | if ($item->objectType === 'post' && $name === 'post_status') { |
| | | return $this->updatePostStatus($item->id, $value); |
| | | } |
| | | |
| | | return match ($item->objectType) { |
| | | 'post' => wp_update_post(['ID' => $item->id, $name => $value]) !== 0, |
| | | 'term' => !is_wp_error(wp_update_term($item->id, $item->wpObject->taxonomy, [ |
| | |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * Update post status with proper WordPress functions |
| | | * |
| | | * WordPress doesn't handle trash/delete via wp_update_post(): |
| | | * - wp_trash_post() required for trashing |
| | | * - wp_delete_post() required for deletion |
| | | * - 'delete' is not even a valid post_status value |
| | | * |
| | | * @param int $postId Post ID |
| | | * @param string $status New status (trash, delete, publish, draft, etc.) |
| | | * @return bool Success |
| | | */ |
| | | protected function updatePostStatus(int $postId, string $status): bool |
| | | { |
| | | // Handle trash status |
| | | if ($status === 'trash') { |
| | | $result = wp_trash_post($postId); |
| | | if ($result === false || $result === null) { |
| | | error_log("[Storage] Failed to trash post {$postId}"); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // Handle permanent deletion |
| | | if ($status === 'delete') { |
| | | $result = wp_delete_post($postId, true); // true = force delete, bypass trash |
| | | if ($result === false || $result === null) { |
| | | error_log("[Storage] Failed to delete post {$postId}"); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // Handle all other statuses (publish, draft, pending, private, future) |
| | | $result = wp_update_post([ |
| | | 'ID' => $postId, |
| | | 'post_status' => $status |
| | | ]); |
| | | |
| | | if ($result === 0 || is_wp_error($result)) { |
| | | $error = is_wp_error($result) ? $result->get_error_message() : 'Unknown error'; |
| | | error_log("[Storage] Failed to update post {$postId} status to {$status}: {$error}"); |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | protected function saveTaxonomyField(Item $item, Field $field): bool |
| | | { |
| | | $taxonomy = jvbCheckBase($field->config['taxonomy']); |
| | | $value = $field->value; |
| | | |
| | | if (empty(trim((string)$value))) { |
| | | wp_set_object_terms($item->id, [], $taxonomy, false); |
| | | return true; |
| | |
| | | set_post_thumbnail($id, $fields['post_thumbnail']); |
| | | unset($fields['post_thumbnail']); |
| | | } |
| | | if (isset($fields['post_thumbnail'])) { |
| | | if (empty($fields['post_thumbnail'])) { |
| | | delete_post_thumbnail($id); |
| | | } else { |
| | | set_post_thumbnail($id, $fields['post_thumbnail']); |
| | | } |
| | | unset($fields['post_thumbnail']); |
| | | } |
| | | if (isset($fields['featured_image'])) { |
| | | set_post_thumbnail($id, $fields['featured_image']); |
| | | if (empty($fields['featured_image'])) { |
| | | delete_post_thumbnail($id); |
| | | } else { |
| | | set_post_thumbnail($id, $fields['featured_image']); |
| | | } |
| | | unset($fields['featured_image']); |
| | | } |
| | | |