[EN] Creating your own WordPress import

Door 30 mei 2016Tips & Trucs

For WordPress there are thousands of import plugins, but the most of them can only import posts, the other one is specific for a theme or custom post type, etc. there are to many to try. But the most advanced and besides the easiest plugin is WP All Import! That plugin can import almost everything and if not, there are some add-ons as well. The downside is, it’s not free. The plugin costs only $99 and includes lifetime updates, support and may be used on unlimited websites! A great deal if you ask me. Not convinced yet? Just try it out before you buy! But this post is about creating your own WordPress import right? Absolutely! I needed a very specific import which didn’t fit in WP All Import plugin so I’ve build a custom import and here is how.

Creating a plugin

The first step is to create a plugin, this is very simple. Create a new folder in the “/wp-content/plugins” folder and name it for example: “import-demo”. Inside that folder create a file “import-demo.php” and place some plugin header information inside it:

<?php
/*
Plugin Name: Import demo
Plugin URI: https://royduineveld.nl
Description: A demo import for my blog
Version: 1.0
Author: Roy Duineveld
Author URI: https://royduineveld.nl
*/

After that you could create some admin menu’s to start the import manually, but I’ll skip that for now because I’m going to run the import from the WordPress cron system.

Getting started with the import

First we need a source, for example a csv or xml file. In this post I assume that you’ve got a xml file:

$xml = simplexml_load_file(file_get_contents('http://domain.com/your-xml-file.xml'));

After that, just loop through the items and create a post for each entry:

$postCreated = array(
	'post_title' 	=> $item->title,
	'post_content' 	=> $item->content,
	'post_excerpt' 	=> $item->excerpt,
	'post_status' 	=> 'publish',
	'post_type' 	=> 'post', // Or "page" or some custom post type
);
$postInsertId = wp_insert_post( $postCreated );

After that we may need some post options / meta’s, for example some fields for the Yoast SEO plugin:

$postOptions = array(
	'_yoast_wpseo_title'	=> $item->title,
	'_yoast_wpseo_metadesc'	=> $item->metadescr,
);
foreach($postOptions as $key=>$value){
	update_post_meta($postInsertId,$key,$value);
}

Adding a featured image

To add a featured image to a post we’ve to “sideload” it and to do it within our import plugin we’ve to “hack” a little bit to catch the attachment id and save it on the post:

add_action('add_attachment','featuredImageTrick');
media_sideload_image($item->image, $postInsertId, $item->title);
remove_action('add_attachment','featuredImageTrick');

With this action hook we need that “featuredImageTrick()” function:

function featuredImageTrick($att_id){
    $p = get_post($att_id);
    update_post_meta($p->post_parent,'_thumbnail_id',$att_id);
}

And we need to make sure we’ve included some WordPress core files:

require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');

Run your import with the WordPress cron

WordPress does have a cron system build in which doesn’t require to setup a cron task on your hosting environment within your control panel or with the “crontab” command on Linux systems. But how is this working? WordPress runs a asynchronously request when someone visits your WordPress website (so the page request doesn’t slow down for the visitor). A function checks the time and the scheduled tasks and runs the task if needed. That’s for example how the WordPress checks for version updates and that’s how the auto updates are handled. We can hook into to this with a simple function. But first we’ve to wrap everything we’ve written into a function and we’ve to created a WordPress action for it:

add_action('import_demo', 'importIt');
function importIt(){
    // The code until now
}

After that we can register two hooks to activate the cron task and deactivate it when the plugin is disabled or removed:

register_activation_hook(__FILE__, 'activateCron');
function activateCron() {
	wp_schedule_event(strtotime('tomorrow midnight'), 'daily', 'import_demo');
}

register_deactivation_hook(__FILE__, 'deactivateCron');
function deactivateCron() {
	wp_clear_scheduled_hook('import_demo');
}

With this setup our import will run at or after 0:00, it depends on when a visitor is coming. If you need to make sure that the cron is running at the specified time you can setup a real cronjob by disabling the default cron behavior with this in your “wp-config.php” file:

define('DISABLE_WP_CRON', true);

After that you can setup a cronjob, for example to run it every 5 minutes:

*/5 * * * * php /path/wp-cron.php

This doesn’t mean your import is running every 5 minutes, this is like a visitor is coming to your website every 5 minutes. So at midnight it will trigger the import.

Remove previous posts before import

Currently we’ve build the import to add posts every night, but it’s not overwriting existing ones from the previous import. The easiest way is to just delete those posts and re-import them. To do this we’ve to identify those imported posts first. Just add a extra post option / meta:

$postOptions = array(
	'imported' => true
);

And after that we can identify them and remove the post with its featured image:

currentPosts = get_posts(array( 
	'post_type' 		=> 'post',
	'post_status' 		=> 'publish',
	'meta_key'			=> 'imported', // Our post options to determined
	'posts_per_page'   	=> 1000
));

foreach($currentPosts as $post){
	if($thumbId = get_post_meta($post->ID,'_thumbnail_id',true)){
		wp_delete_attachment($thumbId,true);
	}
	wp_delete_post( $post->ID, true);
}

Wrapping it up

Congrats! You’ve build your own import for WordPress. You can find the complete “import-demo.php” on Github Gist. Good luck!