slug = $slug;
add_action('admin_menu', array($this, 'add_import_export_buttons'), 20);
add_action('admin_post_kadence_export_posts-' . $slug, array($this, 'handle_export'));
add_action('admin_post_kadence_import_posts-' . $slug, array($this, 'handle_import'));
add_action('admin_notices', array($this, 'display_import_notices'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts'));
add_action('admin_footer', array($this, 'add_import_modal_styles'));
add_filter('bulk_actions-edit-' . $slug, array($this, 'register_bulk_export_action'));
add_filter('handle_bulk_actions-edit-' . $slug, array($this, 'handle_bulk_export'), 10, 3);
}
}
public function handle_bulk_export($redirect_to, $action, $post_ids)
{
if ($action !== 'export_selected') {
return $redirect_to;
}
if (!current_user_can('manage_options')) {
wp_die(__('You do not have sufficient permissions to export content.', 'kadence-blocks'));
}
$this->handle_export($post_ids, false);
}
public function enqueue_scripts($hook) {
if ('edit.php' === $hook && $this->slug === get_current_screen()->post_type) {
wp_register_script(
'kadence-cpt-import-export',
'', // Empty source as we're using inline script
array('jquery'),
'1.0',
true
);
wp_enqueue_script('kadence-cpt-import-export');
wp_add_inline_script('kadence-cpt-import-export', '
jQuery(document).ready(function($) {
// Move buttons to after views
var $buttons = $(".kadence-import-export-buttons");
$buttons.insertAfter(".subsubsub");
// Handle import button click
$("#kadence-reveal-import").on("click", function(e) {
e.preventDefault();
$(".kadence-import-form").slideToggle();
});
});
');
}
}
/**
* Register bulk action
*/
public function register_bulk_export_action($bulk_actions) {
$bulk_actions['export_selected'] = __('Export', 'kadence-blocks');
return $bulk_actions;
}
/**
* Add styles for import modal
*/
public function add_import_modal_styles() {
if (get_current_screen()->post_type !== $this->slug) {
return;
}
?>
slug || empty($_GET['import_status'])) {
return;
}
if ($_GET['import_status'] === 'success') {
?>
slug === $typenow && current_user_can('manage_options') ) {
add_action('admin_notices', array($this, 'render_import_export_buttons'));
}
}
/**
* Render the import/export buttons
*/
public function render_import_export_buttons() {
?>
redirect_with_error( __('You do not have sufficient permissions to export content.', 'kadence-blocks') );
}
if( $check_referrer ) {
check_admin_referer('kadence_export_posts_nonce', 'kadence_export_nonce');
}
$posts_args = array(
'post_type' => $this->slug,
'posts_per_page' => -1,
'post_status' => 'any',
);
if( ! empty( $post_ids ) ) {
$posts_args['post__in'] = $post_ids;
}
$posts = get_posts($posts_args);
$export_data = array(
'post_type' => $this->slug,
'posts' => array(),
'related_posts' => array(),
'relationship_map' => array()
);
$this->processed_posts = array();
$this->relationship_map = array();
foreach ($posts as $post) {
$post_data = $this->prepare_post_for_export($post);
$export_data['posts'][] = $post_data;
$this->processed_posts[] = $post->ID;
$this->get_related_posts_recursive($post->post_content, $export_data['related_posts'], $post->ID);
}
$export_data['related_posts'] = array_values(array_unique($export_data['related_posts'], SORT_REGULAR));
$export_data['relationship_map'] = $this->relationship_map;
$temp_dir = get_temp_dir();
$filename = $this->slug . '_export_' . date('Y-m-d_H-i-s');
$json_file = $temp_dir . $filename . '.json';
$zip_file = $temp_dir . $filename . '.zip';
file_put_contents($json_file, wp_json_encode($export_data));
$zip = new ZipArchive();
$zip->open($zip_file, ZipArchive::CREATE | ZipArchive::OVERWRITE);
$zip->addFile($json_file, 'export.json');
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' . basename($zip_file));
header('Content-Length: ' . filesize($zip_file));
readfile($zip_file);
unlink($json_file);
unlink($zip_file);
}
/**
* Recursively get related posts
*/
private function get_related_posts_recursive($content, &$related_posts, $parent_id = null) {
$blocks = parse_blocks($content);
foreach ($blocks as $block) {
if( in_array( $block['blockName'], $this->kadence_cpt_blocks ) && !empty( $block['attrs']['id'] ) ) {
$nested_id = $block['attrs']['id'];
if ($parent_id !== null) {
if (!isset($this->relationship_map[$parent_id])) {
$this->relationship_map[$parent_id] = [];
}
$this->relationship_map[$parent_id][] = $nested_id;
}
if ( ! in_array( $nested_id, $this->processed_posts ) ) {
$nested_post = get_post( $nested_id );
if ( $nested_post ) {
$related_posts[] = $this->prepare_post_for_export( $nested_post );
$this->processed_posts[] = $nested_id;
$this->get_related_posts_recursive($nested_post->post_content, $related_posts, $nested_id);
}
}
}
if (!empty($block['innerBlocks'])) {
foreach ($block['innerBlocks'] as $inner_block) {
$this->get_related_posts_recursive(serialize_blocks(array($inner_block)), $related_posts, $parent_id);
}
}
}
}
public function handle_import() {
if (!current_user_can('manage_options')) {
$this->redirect_with_error( __('You do not have sufficient permissions to import content.', 'kadence-blocks' ) );
return;
}
check_admin_referer('kadence_import_posts_nonce', 'kadence_import_nonce');
if (!isset($_FILES['import_file'])) {
$this->redirect_with_error( __( 'Please upload a file to import.', 'kadence-blocks' ) );
return;
}
$file = $_FILES['import_file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
$this->redirect_with_error( __('File upload failed.', 'kadence-blocks' ) );
return;
}
if ($file['type'] !== 'application/zip' && $file['type'] !== 'application/x-zip-compressed') {
$this->redirect_with_error( __('Invalid file type. Please upload a ZIP file.', 'kadence-blocks' ) );
return;
}
$temp_dir = get_temp_dir();
$zip = new ZipArchive();
if ($zip->open($file['tmp_name']) === TRUE) {
if ($zip->numFiles > 5) {
$this->redirect_with_error( __('Invalid data in import file.', 'kadence-blocks' ) );
return;
}
$zip->extractTo($temp_dir);
$zip->close();
if (!file_exists($temp_dir . 'export.json')) {
$this->redirect_with_error( __( 'Invalid import file structure. Missing export.json', 'kadence-blocks' ) );
return;
}
$json_content = file_get_contents($temp_dir . 'export.json');
$import_data = json_decode($json_content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->redirect_with_error( __('Invalid JSON data in import file.', 'kadence-blocks' ) );
return;
}
try {
$id_map = array();
if (!empty($import_data['related_posts'])) {
foreach ($import_data['related_posts'] as $related_post) {
$new_id = $this->import_single_post($related_post);
if ($new_id) {
$id_map[$related_post['ID']] = $new_id;
}
}
}
foreach (array_merge($import_data['related_posts'], $import_data['posts']) as $post_data) {
$post_content = $post_data['post_content'];
$updated_content = $this->update_block_ids($post_content, $id_map);
$new_post_id = $id_map[$post_data['ID']] ?? null;
if ($new_post_id) {
wp_update_post(array(
'ID' => $new_post_id,
'post_content' => wp_slash($updated_content)
));
}
}
foreach ($import_data['posts'] as $post_data) {
$this->import_single_post($post_data, $id_map);
}
unlink($temp_dir . 'export.json');
wp_redirect(add_query_arg(
array(
'post_type' => $this->slug,
'import_status' => 'success'
),
admin_url('edit.php')
));
exit;
} catch (Exception $e) {
$this->redirect_with_error('Import failed: ' . $e->getMessage());
return;
}
} else {
$this->redirect_with_error('Failed to process the import file.');
return;
}
}
private function prepare_post_for_export($post) {
$post_data = array(
'ID' => $post->ID,
'post_content' => $post->post_content,
'post_title' => $post->post_title,
'post_excerpt' => $post->post_excerpt,
'post_status' => $post->post_status,
'post_type' => $post->post_type,
'meta' => array()
);
$meta = get_post_custom($post->ID);
foreach ($meta as $key => $values) {
if ( ! in_array( $key, $this->excluded_meta_keys ) ) {
$post_data['meta'][$key] = array_map('maybe_unserialize', $values);
}
}
return $post_data;
}
private function import_single_post($post_data, $id_map = array()) {
$temp_content = $post_data['post_content'];
$post_data['post_content'] = '';
unset($post_data['ID']);
$new_post_id = wp_insert_post($post_data, true);
if (!is_wp_error($new_post_id)) {
if (!empty($post_data['meta'])) {
foreach ($post_data['meta'] as $meta_key => $meta_values) {
foreach ($meta_values as $meta_value) {
add_post_meta($new_post_id, $meta_key, $meta_value);
}
}
}
$updated_content = $this->update_block_ids($temp_content, $id_map);
wp_update_post(array(
'ID' => $new_post_id,
'post_content' => wp_slash($updated_content)
));
return $new_post_id;
}
return false;
}
/**
* Update block ID in content with new ID
*/
private function update_block_ids($content, $id_map) {
$blocks = parse_blocks($content);
foreach ($blocks as &$block) {
if ( in_array( $block['blockName'], $this->kadence_cpt_blocks )
&& !empty($block['attrs']['id'])
&& isset($id_map[$block['attrs']['id']])) {
$block['attrs']['id'] = $id_map[$block['attrs']['id']];
}
if (!empty($block['innerBlocks'])) {
$inner_content = serialize_blocks($block['innerBlocks']);
$updated_inner_content = $this->update_block_ids($inner_content, $id_map);
$block['innerBlocks'] = parse_blocks($updated_inner_content);
}
}
return serialize_blocks($blocks);
}
private function redirect_with_error($message) {
wp_redirect(add_query_arg(
array(
'post_type' => $this->slug,
'import_status' => 'error',
'error_message' => urlencode($message)
),
admin_url('edit.php')
),
302
);
exit;
}
}