normalizer = $normalizer; $this->url_transformer = $url_transformer; $this->metadata_transformer = $metadata_transformer; $this->logger = $logger; } public function bucket(): string { return 'posts'; } /** * @param array> $records Package records. */ public function importRecords( array $records, SyncContext $context ): SyncResult { $created = 0; $updated = 0; $skipped = 0; $conflicts = 0; $mappings = $this->mappings( $context ); $errors = array(); foreach ( $records as $record ) { $normalized = $this->normalizer->post( $record ); $existing = $this->findExistingPostId( (int) $normalized['id'] ); if ( $existing > 0 && 'manual_review' === $context->conflictStrategy() ) { ++$skipped; ++$conflicts; $this->logger->warning( 'Skipped post import because manual review is required.', array( 'source_id' => $normalized['id'], 'post_id' => $existing, ) ); continue; } try { $post_id = $this->savePost( $normalized, $existing, $mappings ); } catch ( ContentImportException $exception ) { $errors[] = $exception->getMessage(); $this->logger->error( $exception->getMessage(), array( 'bucket' => $exception->bucket(), 'record' => $exception->record(), ) ); continue; } if ( $existing > 0 ) { ++$updated; } else { ++$created; } $this->saveMeta( $post_id, $normalized, $context, $mappings ); } if ( array() !== $errors ) { return SyncResult::merge( array( SyncResult::success( array( 'created' => $created, 'updated' => $updated, 'skipped' => $skipped, 'conflicts' => $conflicts, ) ), SyncResult::failure( $errors ), ) ); } $this->logger->info( 'Imported post content records.', array( 'created' => $created, 'updated' => $updated, 'skipped' => $skipped, 'conflicts' => $conflicts, ) ); return SyncResult::success( array( 'created' => $created, 'updated' => $updated, 'skipped' => $skipped, 'conflicts' => $conflicts, ) ); } private function findExistingPostId( int $source_id ): int { if ( $source_id <= 0 ) { return 0; } $posts = get_posts( array( 'post_type' => 'any', // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Source ID lookup is the handler's stable import identity. 'meta_key' => '_wpcs_source_id', 'meta_value' => (string) $source_id, // phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value ) ); if ( array() === $posts ) { return 0; } return (int) $posts[0]->ID; } /** * @param array $record Normalized post record. * @param int $existing Existing post ID. */ private function savePost( array $record, int $existing, UrlMappingCollection $mappings ): int { $post_data = array( 'post_type' => $record['post_type'], 'post_title' => $record['post_title'], 'post_content' => $this->url_transformer->transformString( (string) $record['post_content'], $mappings ), 'post_excerpt' => $this->url_transformer->transformString( (string) $record['post_excerpt'], $mappings ), 'post_status' => $record['post_status'], 'post_name' => $record['post_name'], 'post_parent' => $record['post_parent'], 'menu_order' => $record['menu_order'], ); if ( $existing > 0 ) { $post_data['ID'] = $existing; return $this->postIdFromResult( wp_update_post( $post_data, true ), $record ); } return $this->postIdFromResult( wp_insert_post( $post_data, true ), $record ); } /** * @param int|\WP_Error $result Post save result. * @param array $record Normalized post record. */ private function postIdFromResult( $result, array $record ): int { if ( is_wp_error( $result ) || (int) $result <= 0 ) { throw new ContentImportException( $this->bucket(), $record, sprintf( 'Post import failed for source ID %d.', (int) $record['id'] ) ); } return (int) $result; } /** * @param array $record Normalized post record. */ private function saveMeta( int $post_id, array $record, SyncContext $context, UrlMappingCollection $mappings ): void { update_post_meta( $post_id, '_wpcs_source_id', (int) $record['id'] ); update_post_meta( $post_id, '_wpcs_source_site', $context->sourceUrl() ); foreach ( $record['meta'] as $key => $value ) { update_post_meta( $post_id, (string) $key, $this->metadata_transformer->transformValue( $value, $mappings ) ); } } private function mappings( SyncContext $context ): UrlMappingCollection { $mappings = array(); foreach ( $context->urlMappings() as $source => $destination ) { $mappings[] = new UrlMapping( $source, $destination ); } return new UrlMappingCollection( $mappings ); } }