Export & Import API
WordPress provides APIs for exporting and importing content in WXR (WordPress eXtended RSS) format.
Export API
export_wp()
Main function to generate a WXR export file.
export_wp( array $args = array() );
Parameters:
| Key | Type | Description |
|---|---|---|
content |
string | Content type: ‘all’, ‘post’, ‘page’, ‘attachment’, or custom post type |
author |
int/false | Author ID or false for all |
category |
string/false | Category slug or false for all |
start_date |
string/false | Start date (Y-m-d) |
end_date |
string/false | End date (Y-m-d) |
status |
string/false | Post status or false for all |
Example:
// Export all content
export_wp( array( 'content' => 'all' ) );
// Export posts from specific author
export_wp( array(
'content' => 'post',
'author' => 1,
) );
// Export posts from date range
export_wp( array(
'content' => 'post',
'start_date' => '2024-01-01',
'end_date' => '2024-06-30',
) );
// Export specific category
export_wp( array(
'content' => 'post',
'category' => 'news',
) );
// Export specific status
export_wp( array(
'content' => 'post',
'status' => 'publish',
) );
Programmatic Export
function generate_export_file( $args = array() ) {
require_once ABSPATH . 'wp-admin/includes/export.php';
// Capture output
ob_start();
export_wp( $args );
$xml = ob_get_clean();
return $xml;
}
// Save to file
function save_export_to_file( $args = array() ) {
$xml = generate_export_file( $args );
$upload_dir = wp_upload_dir();
$filename = 'export-' . date( 'Y-m-d' ) . '.xml';
$filepath = $upload_dir['path'] . '/' . $filename;
file_put_contents( $filepath, $xml );
return array(
'file' => $filepath,
'url' => $upload_dir['url'] . '/' . $filename,
);
}
WXR Version
// Current WXR version
define( 'WXR_VERSION', '1.2' );
Export Hooks
| Hook | Description |
|---|---|
export_wp |
Fires at beginning of export |
export_wp_filename |
Filter export filename |
wxr_export_skip_postmeta |
Skip specific post meta |
wxr_export_skip_termmeta |
Skip specific term meta |
wxr_export_skip_commentmeta |
Skip specific comment meta |
Custom Export Filters
// Custom filename
add_filter( 'export_wp_filename', function( $filename, $sitename, $date ) {
return $sitename . '-backup-' . $date . '.xml';
}, 10, 3 );
// Skip specific post meta
add_filter( 'wxr_export_skip_postmeta', function( $skip, $meta_key, $meta ) {
// Skip sensitive data
if ( in_array( $meta_key, array( '_api_key', '_secret' ), true ) ) {
return true;
}
return $skip;
}, 10, 3 );
Import API
Register an Importer
register_importer(
string $id,
string $name,
string $description,
callable $callback
);
Example:
add_action( 'admin_init', 'register_my_importer' );
function register_my_importer() {
register_importer(
'my-importer',
__( 'My Custom Importer' ),
__( 'Import content from My Format.' ),
'my_importer_callback'
);
}
function my_importer_callback() {
// Display importer interface
// Handle file upload and processing
}
Get Registered Importers
$importers = get_importers();
foreach ( $importers as $id => $data ) {
echo $data[0]; // Name
echo $data[1]; // Description
// $data[2] is the callback
}
Popular Importers
// Get list of popular importers from wordpress.org
$importers = wp_get_popular_importers();
/*
array(
'wordpress' => array(
'name' => 'WordPress',
'description' => 'Import posts, pages...',
'plugin-slug' => 'wordpress-importer',
'importer-id' => 'wordpress',
),
'blogger' => array(...),
// ...
)
*/
Import Upload Handling
// Handle importer file upload
$result = wp_import_handle_upload();
if ( isset( $result['error'] ) ) {
echo $result['error'];
} else {
$file = $result['file']; // File path
$id = $result['id']; // Attachment ID
// Process the file...
// Clean up when done
wp_import_cleanup( $id );
}
Building a Custom Importer
Basic Structure
class My_Custom_Importer {
public function __construct() {
// Initialize
}
public function dispatch() {
$step = isset( $_GET['step'] ) ? (int) $_GET['step'] : 0;
switch ( $step ) {
case 0:
$this->upload_form();
break;
case 1:
check_admin_referer( 'import-upload' );
$this->handle_upload();
break;
case 2:
check_admin_referer( 'import-my-format' );
$this->import();
break;
}
}
private function upload_form() {
?>
<div class="wrap">
<h1><?php _e( 'My Format Importer' ); ?></h1>
<form enctype="multipart/form-data" method="post"
action="<?php echo esc_url( admin_url( 'admin.php?import=my-importer&step=1' ) ); ?>">
<?php wp_nonce_field( 'import-upload' ); ?>
<p>
<label for="upload"><?php _e( 'Choose a file:' ); ?></label>
<input type="file" name="import" id="upload">
</p>
<?php submit_button( __( 'Upload and Import' ) ); ?>
</form>
</div>
<?php
}
private function handle_upload() {
$file = wp_import_handle_upload();
if ( isset( $file['error'] ) ) {
echo '<p class="error">' . esc_html( $file['error'] ) . '</p>';
return;
}
// Store file info for next step
$this->id = $file['id'];
$this->file = $file['file'];
// Show mapping options or proceed to import
$this->show_options();
}
private function show_options() {
?>
<form method="post"
action="<?php echo esc_url( admin_url( 'admin.php?import=my-importer&step=2' ) ); ?>">
<?php wp_nonce_field( 'import-my-format' ); ?>
<input type="hidden" name="import_id" value="<?php echo esc_attr( $this->id ); ?>">
<h3><?php _e( 'Import Options' ); ?></h3>
<p>
<label>
<input type="checkbox" name="import_attachments" value="1" checked>
<?php _e( 'Download and import attachments' ); ?>
</label>
</p>
<?php submit_button( __( 'Submit' ) ); ?>
</form>
<?php
}
private function import() {
$import_id = isset( $_POST['import_id'] ) ? (int) $_POST['import_id'] : 0;
$file = get_attached_file( $import_id );
if ( ! $file || ! file_exists( $file ) ) {
echo '<p class="error">' . __( 'Import file not found.' ) . '</p>';
return;
}
// Process the import
$this->process_file( $file );
// Clean up
wp_import_cleanup( $import_id );
echo '<p>' . __( 'Import complete!' ) . '</p>';
}
private function process_file( $file ) {
// Read and parse the file
$content = file_get_contents( $file );
// Process content...
// Insert posts, terms, etc.
}
}
// Register the importer
add_action( 'admin_init', function() {
$importer = new My_Custom_Importer();
register_importer(
'my-importer',
__( 'My Format' ),
__( 'Import from My Format' ),
array( $importer, 'dispatch' )
);
} );
WP_Importer Base Class
WordPress provides a base class for importers.
require_once ABSPATH . 'wp-admin/includes/class-wp-importer.php';
class My_Importer extends WP_Importer {
// Get authors from import file
function get_authors_from_import( $import_data ) {
// Return array of authors
}
// Map import users to existing users
function get_author_mapping() {
// Return author mapping array
}
}
Inserting Imported Content
Posts
function import_post( $data ) {
$post_data = array(
'post_title' => sanitize_text_field( $data['title'] ),
'post_content' => wp_kses_post( $data['content'] ),
'post_excerpt' => sanitize_text_field( $data['excerpt'] ),
'post_status' => $data['status'] ?? 'publish',
'post_type' => $data['type'] ?? 'post',
'post_date' => $data['date'] ?? current_time( 'mysql' ),
'post_author' => $data['author'] ?? get_current_user_id(),
);
$post_id = wp_insert_post( $post_data, true );
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
// Add meta
if ( isset( $data['meta'] ) ) {
foreach ( $data['meta'] as $key => $value ) {
update_post_meta( $post_id, $key, $value );
}
}
// Add terms
if ( isset( $data['categories'] ) ) {
wp_set_post_categories( $post_id, $data['categories'] );
}
if ( isset( $data['tags'] ) ) {
wp_set_post_tags( $post_id, $data['tags'] );
}
return $post_id;
}
Terms
function import_term( $data ) {
$term = wp_insert_term(
$data['name'],
$data['taxonomy'],
array(
'description' => $data['description'] ?? '',
'slug' => $data['slug'] ?? '',
'parent' => $data['parent'] ?? 0,
)
);
if ( is_wp_error( $term ) ) {
// Term might already exist
$existing = get_term_by( 'slug', $data['slug'], $data['taxonomy'] );
if ( $existing ) {
return $existing->term_id;
}
return $term;
}
return $term['term_id'];
}
Users
function import_user( $data ) {
// Check if user exists
$user = get_user_by( 'email', $data['email'] );
if ( $user ) {
return $user->ID;
}
$user_data = array(
'user_login' => $data['username'],
'user_email' => $data['email'],
'user_pass' => wp_generate_password(),
'first_name' => $data['first_name'] ?? '',
'last_name' => $data['last_name'] ?? '',
'role' => $data['role'] ?? 'subscriber',
);
return wp_insert_user( $user_data );
}
Attachments
function import_attachment( $url, $post_id = 0 ) {
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
// Download file
$tmp = download_url( $url );
if ( is_wp_error( $tmp ) ) {
return $tmp;
}
$file_array = array(
'name' => basename( parse_url( $url, PHP_URL_PATH ) ),
'tmp_name' => $tmp,
);
// Sideload
$attachment_id = media_handle_sideload( $file_array, $post_id );
if ( is_wp_error( $attachment_id ) ) {
@unlink( $file_array['tmp_name'] );
}
return $attachment_id;
}
Import Progress
For large imports, track progress:
class Progressive_Importer {
private $batch_size = 50;
private $progress_option = 'my_import_progress';
public function start_import( $file ) {
$data = $this->parse_file( $file );
update_option( $this->progress_option, array(
'total' => count( $data ),
'processed' => 0,
'data' => $data,
) );
return $this->process_batch();
}
public function process_batch() {
$progress = get_option( $this->progress_option );
if ( ! $progress ) {
return array( 'complete' => true );
}
$start = $progress['processed'];
$batch = array_slice( $progress['data'], $start, $this->batch_size );
foreach ( $batch as $item ) {
$this->import_item( $item );
$progress['processed']++;
}
if ( $progress['processed'] >= $progress['total'] ) {
delete_option( $this->progress_option );
return array(
'complete' => true,
'total' => $progress['total'],
);
}
update_option( $this->progress_option, $progress );
return array(
'complete' => false,
'processed' => $progress['processed'],
'total' => $progress['total'],
'percent' => round( ( $progress['processed'] / $progress['total'] ) * 100 ),
);
}
}
Best Practices
- Validate Input: Always validate imported data
- Sanitize: Sanitize all content before insertion
- Handle Duplicates: Check for existing content
- Batch Processing: Process large imports in batches
- Progress Feedback: Show import progress to users
- Error Logging: Log import errors for debugging
- Cleanup: Always clean up temporary files
- Memory Management: Use
wp_suspend_cache_addition()for large imports
function large_import() {
// Disable cache during import
wp_suspend_cache_addition( true );
// Disable term counting
wp_defer_term_counting( true );
// Process import...
// Re-enable
wp_defer_term_counting( false );
wp_suspend_cache_addition( false );
// Clean up term counts
wp_update_term_count_now();
}