Posts_Import
Class Posts_Import
Source
File: includes/libs/posts-import.class.php
class Posts_Import{
	/**
	 * @var Post_Type
	 */
	protected $post_type;
	/**
	 * Posts_Import constructor.
	 *
	 * @param Post_Type $post_type
	 */
	public function __construct( Post_Type $post_type ) {
		$this->post_type = $post_type;
	}
	/**
	 * Imports videos from a given feed source.
	 * Used by automatic updates.
	 *
	 * @param $raw_feed
	 * @param Feed|array $import_options
	 *
	 * @return array|void
	 */
	public function run_import( $raw_feed, $import_options ){
		/**
		 * @var array $native_tax
		 * @var array $native_tag
		 * @var bool $import_description
		 * @var string $import_status
		 * @var bool $import_title
		 * @var bool $import_date
		 * @var int $import_user
		 */
		extract( $this->get_import_options( $import_options ), EXTR_SKIP );
		// get import options
		$options = Plugin::instance()->get_options();
		// overwrite plugin import settings with import settings
		$options['import_description'] = $import_description;
		$options['import_status'] = $import_status;
		$options['import_title'] = $import_title;
		// store results
		$result = [
			'private' 	=> 0,
			'imported' 	=> 0,
			'skipped' 	=> 0,
			'total'		=> count( $raw_feed ),
			'ids'		=> [],
			'error'		=> []
		];
		$duplicates = $this->get_duplicate_posts( $raw_feed, $this->post_type->get_post_type() );
		// parse feed
		foreach( $raw_feed as $video ){
			// video already exists, don't do anything
			if( array_key_exists( $video['video_id'], $duplicates ) ){
				/**
				 * Generate an error and pass it for debugging
				 * @var WP_Error
				 */
				$error = new WP_Error(
					'cvm_import_skip_existing_video',
					sprintf(
						'%s %s',
						sprintf(
							__( 'Skipped video having ID %s because it already exists.', 'codeflavors-vimeo-video-post-lite' ),
							$video['video_id']
						),
						sprintf(
							__( 'Existing post has ID %s.', 'codeflavors-vimeo-video-post-lite' ),
							$duplicates[ $video['video_id'] ][0]
						)
					),
					[
						'video_data' => $video,
						'existing_posts' => $duplicates[ $video['video_id'] ]
					]
				);
				$result['error'][] = $error;
				/**
				 * Pass error to debug function
				 */
				Helper::debug_message(
					'Import error: ' . $error->get_error_message(),
					"\n",
					$error
				);
				foreach( $duplicates[ $video['video_id'] ] as $_post_id ){
					// retrieve the post object for backwards compatibility
					$post = get_post( $_post_id );
					/**
					 * Action triggered when duplicate posts were detected.
					 * Can be used to set extra taxonomies for already existing posts.
					 *
					 * @param \WP_Post $post             The WordPress post object that was found as duplicate.
					 * @param string $taxonomy           The taxonomy that must be imported for the post.
					 * @param string $taxonomy_value     The plugin taxonomy that must be set up.
					 * @param string $tag_taxonomy       The tag taxonomy that must be set up.
					 * @param string $tag_taxonomy_value The tag taxonomy value that must be set for the post.
					 */
					do_action( 'vimeotheque\import_duplicate_taxonomies',
						$post,
						$this->post_type->get_post_tax(),
						$native_tax,
						$this->post_type->get_tag_tax(),
						$native_tag
					);
				}
				$result['skipped'] += 1;
				continue;
			}
			if( 'private' == $video['privacy'] ){
				$result['private'] += 1;
				if( 'skip' == $options['import_privacy'] ){
					$result['skipped'] += 1;
					/**
					 * Generate an error and pass it for debugging
					 * @var WP_Error
					 */
					$error = new WP_Error(
						'cvm_import_skip_private_video',
						sprintf(
							__( 'Skipped private video having ID %s because of plugin settings.', 'cvm-video' ),
							$video['video_id']
						),
						[
							'video_data' => $video
						]
					);
					$result['error'][] = $error;
					/**
					 * Send error to debug function
					 */
					Helper::debug_message(
						'Import error: ' . $error->get_error_message(),
						"\n",
						$error
					);
					continue;
				}
			}
			$post_id = $this->import_video( [
				'video' 		=> $video, // video details retrieved from Vimeo
				'category' 		=> $native_tax, // category name (if any) - will be created if category_id is false
				'tags'			=> $native_tag,
				'user'			=> ( isset( $import_user ) ? absint( $import_user ) : false ), // save as a given user if any
				'post_format'	=> 'video', // post format will default to video
				'status'		=> $this->post_type->get_post_settings()->post_status( $import_status ), // post status
				'options'		=> $options
			] );
			if( $post_id ){
				$result['imported'] += 1;
				$result['ids'][] = $post_id;
				$video = Helper::get_video_post( $post_id );
				$video->set_embed_options(
					$this->get_import_options( $import_options ),
					true
				);
			}
		}
		Helper::debug_message(
			sprintf(
				'Processed %d entries: created %d posts, skipped %d entries, %d entries were marked private.',
				$result['total'],
				$result['imported'],
				$result['skipped'],
				$result['private']
			)
		);
		return $result;
	}
	/**
	 * @param array $raw_feed
	 * @param $post_type
	 *
	 * @return array
	 */
	public function get_duplicate_posts( $raw_feed, $post_type ){
		if( !$raw_feed ){
			return [];
		}
		$video_ids = [];
		foreach( $raw_feed as $video ){
			$video_ids[] = $video['video_id'];
		}
		/**
		 * @var \WP_Query
		 */
		global $wpdb;
		$query = $wpdb->prepare(
			"
			SELECT {$wpdb->postmeta}.post_id, {$wpdb->postmeta}.meta_value 
			FROM {$wpdb->postmeta}
			LEFT JOIN {$wpdb->posts}
			ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID
			WHERE
			{$wpdb->posts}.post_type LIKE '%s' 
			AND meta_value IN(" . implode( ',', $video_ids ) . ")
			",
			$post_type
		);
		$existing = $wpdb->get_results( $query );
		$_result = [];
		if( $existing ){
			foreach( $existing as $r ){
				$_result[ $r->meta_value ][] = $r->post_id;
			}
		}
		/**
		 * Filter the duplicate posts found by the plugin.
		 * When perfoming imports, the filter runs when duplicate imports are detected.
		 *
		 * @param array $_result    The post IDs found as duplicates.
		 */
		$result = apply_filters( 'vimeotheque\duplicate_posts_found', $_result );
		if( $_result !== $result ){
			Helper::debug_message(
				sprintf(
					'Detected duplicate posts override by filter "%s".',
					'vimeotheque\duplicate_posts_found'
				)
			);
		}
		return $result;
	}
	/**
	 * Import a single video based on the passed data
	 *
	 * @param array $args
	 *
	 * @return bool|int
	 */
	public function import_video( $args = [] ){
		$defaults = [
			'video' 			=> [], // video details retrieved from Vimeo
			'post_id'           => false,
			'category' 			=> false, // category name (if any) - will be created if category_id is false
			'tags'				=> false,
			'user'				=> false, // save as a given user if any
			'post_format'		=> 'video', // post format will default to video
			'status'			=> 'draft', // post status
			'options'			=> false,
		];
		/**
		 * @var array $video
		 * @var int $post_id
		 * @var string $category
		 * @var array $tags
		 * @var int $user
		 * @var string $post_format
		 * @var string $status
		 * @var array $options
		 */
		extract( wp_parse_args( $args, $defaults ), EXTR_SKIP );
		if( !$options ){
			$options = Plugin::instance()->get_options();
		}
		// if no video details, bail out
		if( !$video ){
			return false;
		}
		/**
		 * Filter that allows changing of post format when importing videos.
		 *
		 * @param string $post_format   The post format.
		 */
		$post_format = apply_filters(
			'vimeotheque\import_post_format',
			$post_format
		);
		/**
		 * Filter that allows video imports.
		 * Can be used to prevent importing of videos.
		 *
		 * @param bool $allow       Allow video improts to be made (true) or prevent them (false).
		 * @param array $video      Video details array.
		 * @param string $post_type The post type that should be created from the video details.
		 * @param false $false      An unset parameter.
		 */
		$allow_import = apply_filters(
			'vimeotheque\allow_import',
			true,
			$video,
			$this->post_type->get_post_type(),
			false
		);
		if( !$allow_import ){
			/**
			 * Generate an error and pass it for debugging
			 * @var WP_Error
			 */
			$error = new WP_Error(
				'vimeotheque_video_import_prevented_by_filter',
				sprintf(
					__( 'Video having ID %s could not be imported because of a filter blocking all imports.', 'codeflavors-vimeo-video-post-lite' ),
					$video['video_id']
				),
				[ 'video_data' => $video ]
			);
			/**
			 * Send error to debug function
			 */
			Helper::debug_message(
				'Import error: ' . $error->get_error_message(),
				"\n",
				$error
			);
			return false;
		}
		// plugin settings; caller can pass their own import options
		if( !$options ){
			$options = Plugin::instance()->get_options();
		}
		if( 'private' == $video['privacy'] && 'pending' == $options['import_privacy'] ){
			$status = 'pending';
		}
		// post content
		$post_content = '';
		if( 'content' == $options['import_description'] || 'content_excerpt' == $options['import_description'] ){
			$post_content = $video['description'];
		}
		// post excerpt
		$post_excerpt = '';
		if( 'excerpt' == $options['import_description'] || 'content_excerpt' == $options['import_description'] ){
			$post_excerpt = $video['description'];
		}
		// post title
		$post_title 	= $options['import_title'] ? $video['title'] : '';
		/**
		 * Action that runs before the post is inserted into the database.
		 *
		 * @param array $video  The video details array retrieved from Vimeo.
		 * @param false $false  Always false in Vimeotheque Lite.
		 */
		do_action(
			'vimeotheque\import_before',
			$video,
			false
		);
		// set post data
		$post_data = [
			/**
			 * Post title filter before the post is inserted into the database.
			 *
			 * @param string $title     The post title.
			 * @param array $video      The video details.
			 * @param bool $false       Unused parameter.
			 */
			'post_title' 	=> apply_filters(
				'vimeotheque\import_post_title',
				$post_title,
				$video,
				false
			),
			/**
			 * Post content filter before the post is inserted into the database.
			 *
			 * @param string $content   The post content.
			 * @param array $video      The video details.
			 * @param false $false      Unused parameter.
			 */
			'post_content' 	=> apply_filters(
				'vimeotheque\import_post_content',
				$post_content,
				$video,
				false
			),
			/**
			 * Post excerpt filter before the post is inserted into the database.
			 *
			 * @param string $excerpt   The post excerpt.
			 * @param array $video      The video details.
			 * @param false $false      Unused parameter.
			 */
			'post_excerpt'	=> apply_filters(
				'vimeotheque\import_post_excerpt',
				$post_excerpt,
				$video,
				false
			),
			'post_type'		=> $this->post_type->get_post_type(),
			/**
			 * Post status filter before the post is inserted into the database.
			 *
			 * @param string $status    The post status.
			 * @param array $video      The video details.
			 * @param false $false      Unused parameter.
			 */
			'post_status'	=> apply_filters(
				'vimeotheque\import_post_status',
				$status,
				$video,
				false
			)
		];
		$pd = $options['import_date'] ? date('Y-m-d H:i:s', strtotime( $video['published'] )) : current_time( 'mysql' );
		/**
		 * Post date filter before the post is inserted into the database.
		 *
		 * @param string $date      The post date.
		 * @param array $video      The video details.
		 * @param false $false      Unused parameter.
		 */
		$post_date = apply_filters(
			'vimeotheque\import_post_date',
			$pd,
			$video,
			false
		);
		if( isset( $options['import_date'] ) && $options['import_date'] ){
			$post_data['post_date_gmt'] = $post_date;
			$post_data['edit_date']		= $post_date;
			$post_data['post_date']		= $post_date;
		}
		// set user
		if( $user ){
			$post_data['post_author'] = $user;
		}
		/**
		 * @var int|\WP_Error $post_id
		 */
		// single video import will pass post ID
		if( isset( $post_id ) && $post_id ){
			$post_data['ID'] = $post_id;
			$post_id = wp_update_post( $post_data, true );
		}else {
			// allow empty insert into post content
			add_filter(
				'wp_insert_post_empty_content',
				'__return_false'
			);
			$post_id = wp_insert_post( $post_data, true );
		}
		if( is_wp_error( $post_id ) ){
			Helper::debug_message(
				sprintf(
					'Video with ID %s generated the following database error on insert: "%s"; video post could not be created.',
					$video['video_id'],
					$post_id->get_error_message()
				)
			);
		}
		// check if post was created
		if( !is_wp_error( $post_id ) ){
			// set post format
			if( $post_format  ){
				set_post_format( $post_id, $post_format );
			}
			// set post category
			if( $category ){
				$category = is_array( $category ) ? $category : [ $category ];
				wp_set_post_terms( $post_id, $category, $this->post_type->get_post_tax() );
			}
			if( $tags ){
				wp_set_post_terms( $post_id, $tags, $this->post_type->get_tag_tax() );
			}
			// insert tags
			if( ( isset( $options['import_tags'] ) && $options['import_tags'] ) && $this->post_type->get_tag_tax() ){
				if( isset( $video['tags'] ) && is_array( $video['tags'] ) ){
					$count = absint( $options['max_tags'] );
					$tags = array_slice( $video['tags'], 0, $count );
					if( $tags ){
						wp_set_post_terms( $post_id, $tags, $this->post_type->get_tag_tax(), true );
					}
				}
			}
			// set post meta
			$_post = Helper::get_video_post( $post_id );
			$_post->set_video_data( $video );
			$_post->set_video_id_meta();
			$_post->set_video_url_meta();
			/**
			 * Action after a video post was successfully imported into the database.
			 *
			 * @param int $post_id          ID of the post newly created from the Vimeo video.
			 * @param array $video          Array of video details retrieved from Vimeo.
			 * @param false $unknown        Unused parameter.
			 * @param string $post_type     The post type that was created.
			 */
			do_action(
				'vimeotheque\import_success',
				$post_id,
				$video,
				false,
				$this->post_type->get_post_type()
			);
			/**
			 * Send a debug message
			 */
			Helper::debug_message(
				sprintf(
					'Imported video ID %s into post #%d having post type "%s".',
					$video['video_id'],
					$post_id,
					$this->post_type->get_post_type()
				)
			);
			// import image
			if( $options['featured_image'] ){
				$_post->set_featured_image();
			}
			return $post_id;
		}// end checking if not wp error on post insert
		return false;
	}
	/**
	 * Process the import options
	 *
	 * @param array $source
	 *
	 * @return array
	 */
	private function get_import_options( $source = [] ){
		$taxonomy = $this->post_type->get_post_tax();
		$tag_tax = $this->post_type->get_tag_tax();
		$native_tax = isset( $source['tax_input'][ $taxonomy ] ) ? (array) $source['tax_input'][ $taxonomy ] : [];
		$native_tag = isset( $source['tax_input'][ $tag_tax ] ) ? (array) $source['tax_input'][ $tag_tax ] : [];
		$import_options = [
			'native_tax'		=> $native_tax,
			'native_tag'		=> $native_tag,
			'import_description' => $source['import_description'],
			'import_status' => $source['import_status'],
			'import_title' => isset( $source['import_title'] )
		];
		return $import_options;
	}
}
			Methods
- __construct — Posts_Import constructor.
 - get_duplicate_posts
 - get_import_options — Process the import options
 - import_video — Import a single video based on the passed data
 - run_import — Imports videos from a given feed source.
 
