HEX
Server: Apache/2.4.65 (Debian)
System: Linux 88f31f35b0b8 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/adnkronos/src/Import/PostCreator.php
<?php

namespace AdnKronos\Import;

use AdnKronos\Feed\FeedItem;
use AdnKronos\Psr\Log\LoggerInterface;
use WP_Query;

/**
 * Creates a WordPress post from a FeedItem.
 * Handles deduplication (guid check), meta fields, image import, and tagging.
 * Works for both article and video items — the content difference is already
 * encoded in FeedItem by the respective parser.
 */
class PostCreator {

    /** @var ImageImporter */
    private $imageImporter;

    /** @var LoggerInterface */
    private $logger;

    public function __construct(ImageImporter $imageImporter, LoggerInterface $logger) {
        $this->imageImporter = $imageImporter;
        $this->logger        = $logger;
    }

    /**
     * Creates a post. Returns the new post ID, or null if already imported.
     *
     * @param FeedItem $item
     * @param int      $categoryId       WP category term ID
     * @param string   $postStatus       'publish' or 'draft'
     * @param string   $ownerEmail
     * @param string   $feedCode         Used as WP tag
     * @param bool     $skipImages
     * @param string   $imageOwnerEmail
     * @return int|null
     */
    public function create(
        FeedItem $item,
        $categoryId,
        $postStatus,
        $ownerEmail,
        $feedCode,
        $skipImages,
        $imageOwnerEmail
    ) {
        $this->logger->info('Evaluating: [' . $item->guid . '], feed: [' . $feedCode . ']');

        if ($this->existsByGuid($item)) {
            $this->logger->info('Skipping (already imported): ' . $item->guid);
            return null;
        }

        $postOwner    = get_user_by('email', $ownerEmail);
        $postAuthorId = $postOwner ? $postOwner->ID : 0;
        if (!$postOwner && !empty($ownerEmail)) {
            $this->logger->warning('PostCreator: owner not found for email [' . $ownerEmail . '], using author ID 0');
        }

        $this->logger->info('Importing ' . $item->guid);

        // $item->date is UTC. post_date must be in WP local timezone;
        // post_date_gmt must be UTC. Providing both prevents WordPress from
        // recomputing one from the other and avoids spurious future-post scheduling.
        $postId = wp_insert_post(array(
            'post_title'     => $item->title,
            'post_content'   => $item->content,
            'post_date'      => get_date_from_gmt($item->date),
            'post_date_gmt'  => $item->date,
            'post_status'    => $postStatus,
            'post_author'    => $postAuthorId,
            'post_category'  => array($categoryId),
        ));

        if (!$postId || is_wp_error($postId)) {
            $this->logger->error('wp_insert_post failed for guid ' . $item->guid);
            return null;
        }

        update_post_meta($postId, 'adkn_guid_post_feed', $item->guid);
        update_post_meta($postId, 'adkn_feed_category', sanitize_text_field($item->feedCategory));

        if (!$skipImages && $item->imageUrl) {
            $this->imageImporter->import($postId, $item->imageUrl, $item->title, $imageOwnerEmail);
        }

        wp_set_post_tags($postId, array($feedCode));

        return $postId;
    }

    /**
     * @param FeedItem $item
     * @return bool
     */
    private function existsByGuid(FeedItem $item) {
        $guid = trim($item->guid);

        $query = new WP_Query(array(
            'post_type'              => 'post',
            'post_status'            => 'any',
            'posts_per_page'         => 1,
            'fields'                 => 'ids',
            'no_found_rows'          => true,
            'update_post_meta_cache' => false,
            'update_post_term_cache' => false,
            'meta_key'               => 'adkn_guid_post_feed',
            'meta_value'             => $guid,
        ));

        $this->logExistingGuid($item, $query);
        return $query->post_count > 0;
    }

    /**
     * @param FeedItem $item
     * @param WP_Query $query
     *
     * @return void
     */
    private function logExistingGuid(FeedItem $item, $query) {
        if ($query->post_count == 0) {
            return;
        }

        $incomingFeedItem = array(
            'guid'           => trim($item->guid),
            'title'          => $item->title,
            'date'           => $item->date,
            'feed_category'  => $item->feedCategory,
            'image_url'      => $item->imageUrl,
            'content_length' => strlen($item->content),
        );

        $existingPosts = array_map(function ($postId) {
            return array(
                'id'                 => $postId,
                'title'              => get_the_title($postId),
                'status'             => get_post_status($postId),
                'type'               => get_post_type($postId),
                'date'               => get_post_field('post_date', $postId),
                'wp_guid'            => get_post_field('guid', $postId),
                'permalink'          => get_permalink($postId),
                'feed_guid_meta'     => get_post_meta($postId, 'adkn_guid_post_feed', true),
                'feed_category_meta' => get_post_meta($postId, 'adkn_feed_category', true),
            );
        }, $query->posts);

        $this->logger->debug(
            sprintf('Already imported matched guid; incoming feed guid: [%s]', trim($item->guid)),
            array(
                'incoming_feed_item' => $incomingFeedItem,
                'existing_posts'     => $existingPosts,
            )
        );
    }
}