From f3c57e43bc247ce78ff60a2ee9d9d9e508a06510 Mon Sep 17 00:00:00 2001 From: Nika Siradze Date: Tue, 30 Jun 2026 17:03:13 +0400 Subject: [PATCH] ACF-aware meta writes + per-source post type for feeds - Meta::write uses ACF update_field() when ACF is active, so mapped/rule values land in the matching ACF field (with its field-key reference) instead of a bare meta row; falls back to update_post_meta otherwise. Used by FieldMapper output, scrape rules, and both rule refreshers. - Per-source post type now applies to ALL sources (feeds too), not just scrapers: PostFactory::create() and assign_terms() honor the source's post type; the 'Save items as (post type)' field shows for every source. --- src/Admin/Admin.php | 8 ++++++-- src/Admin/views/sources.php | 2 +- src/Maintenance/GlobalRulesRefresher.php | 3 ++- src/Maintenance/RulesRefresher.php | 3 ++- src/Publish/Meta.php | 21 +++++++++++++++++++++ src/Publish/PostFactory.php | 17 +++++++++-------- 6 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 src/Publish/Meta.php diff --git a/src/Admin/Admin.php b/src/Admin/Admin.php index ff7485c..12d3d40 100644 --- a/src/Admin/Admin.php +++ b/src/Admin/Admin.php @@ -405,6 +405,8 @@ public function handle_save_source(): void { $categories = $this->infer_categories_from_feed_url( $url ); } + $post_type = sanitize_key( wp_unslash( $_POST['post_type'] ?? '' ) ); + $settings = [ 'interval_minutes' => $interval, 'categories' => $categories, @@ -413,11 +415,14 @@ public function handle_save_source(): void { 'include_keywords' => $include, 'exclude_keywords' => $exclude, 'article_length' => $length, + 'post_type' => $post_type, ]; if ( sanitize_key( wp_unslash( $_POST['source_type'] ?? 'rss' ) ) === 'scrape' ) { $settings = array_merge( $settings, $this->scrape_settings_from_post() ); - \AggregateIt\Source\ScraperPostTypes::remember( (string) $settings['post_type'] ); + } + if ( $post_type !== '' ) { + \AggregateIt\Source\ScraperPostTypes::remember( $post_type ); } $repo = $this->plugin->sources(); @@ -490,7 +495,6 @@ private function scrape_settings_from_post(): array { return [ 'source_type' => 'scrape', - 'post_type' => sanitize_key( wp_unslash( $_POST['post_type'] ?? '' ) ), 'processing' => in_array( $processing, [ 'passthrough', 'rewrite' ], true ) ? $processing : 'passthrough', 'scrape' => [ 'discovery' => [ diff --git a/src/Admin/views/sources.php b/src/Admin/views/sources.php index 469514b..ec07904 100644 --- a/src/Admin/views/sources.php +++ b/src/Admin/views/sources.php @@ -145,7 +145,7 @@ value="url ?? '' ); ?>" placeholder="https://example.com/feed"> - + $value ) { - update_post_meta( $id, sanitize_key( (string) $key ), $value ); + Meta::write( (int) $id, sanitize_key( (string) $key ), $value ); } } diff --git a/src/Publish/Meta.php b/src/Publish/Meta.php new file mode 100644 index 0000000..3ab99d5 --- /dev/null +++ b/src/Publish/Meta.php @@ -0,0 +1,21 @@ +slugs->generate( $slug !== '' ? $slug : $keyword, $title ); - $source = $item->source_id ? $this->sources->get( $item->source_id ) : null; - $status = $source ? $source->publish_status( $this->settings->publish_status() ) : $this->settings->publish_status(); + $source = $item->source_id ? $this->sources->get( $item->source_id ) : null; + $status = $source ? $source->publish_status( $this->settings->publish_status() ) : $this->settings->publish_status(); + $post_type = $source && $source->post_type_connection() !== '' ? $source->post_type_connection() : $this->settings->target_post_type(); $post_id = wp_insert_post( [ - 'post_type' => $this->settings->target_post_type(), + 'post_type' => $post_type, 'post_status' => $status, 'post_title' => $title, 'post_name' => $slug, @@ -53,7 +54,7 @@ public function create( int $cluster_id, Item $item, array $structured, string $ update_post_meta( $post_id, '_ai_schema_type', $item->flags['schema_type'] ?? 'Article' ); update_post_meta( $post_id, '_ai_prompt_version', AGGREGATE_IT_VERSION ); - $this->assign_terms( (int) $post_id, $item->source_id, (string) ( $structured['category'] ?? '' ) ); + $this->assign_terms( (int) $post_id, $post_type, $item->source_id, (string) ( $structured['category'] ?? '' ) ); return (int) $post_id; } @@ -62,9 +63,9 @@ public function create( int $cluster_id, Item $item, array $structured, string $ * Categorize by the AI's per-article topic (created on first use), falling back to the * feed's configured categories when the AI gives nothing. Tags come from the feed. */ - private function assign_terms( int $post_id, int $source_id, string $ai_category ): void { + private function assign_terms( int $post_id, string $post_type, int $source_id, string $ai_category ): void { $source = $source_id ? $this->sources->get( $source_id ) : null; - $taxes = get_object_taxonomies( $this->settings->target_post_type() ); + $taxes = get_object_taxonomies( $post_type ); if ( in_array( 'category', $taxes, true ) ) { $ids = []; @@ -129,7 +130,7 @@ public function create_mapped( Item $item ): int { update_post_meta( $post_id, '_ai_prompt_version', AGGREGATE_IT_VERSION ); foreach ( $mapped['meta'] as $key => $value ) { - update_post_meta( $post_id, sanitize_key( (string) $key ), $value ); + Meta::write( $post_id, sanitize_key( (string) $key ), $value ); } foreach ( $mapped['terms'] as $taxonomy => $names ) { if ( taxonomy_exists( (string) $taxonomy ) ) { @@ -140,7 +141,7 @@ public function create_mapped( Item $item ): int { $rules = $source ? $source->rules() : []; if ( $rules ) { foreach ( Rules::apply( $values, $rules, time() ) as $key => $value ) { - update_post_meta( $post_id, sanitize_key( (string) $key ), $value ); + Meta::write( $post_id, sanitize_key( (string) $key ), $value ); } update_post_meta( $post_id, '_ai_rule_values', wp_json_encode( $values ) ); update_post_meta( $post_id, '_ai_source_id', (int) $item->source_id );