Migration Guide - Jankx 1.0 to 2.0
Table of Contents
Migration Guide - Jankx 1.0 to 2.0
Overview
Hướng dẫn migration từ Jankx 1.0 Post Layout system (PHP classes + template engine) sang Jankx 2.0 (Gutenberg Patterns + Dynamic Query Loop).
Key Changes
Component | Jankx 1.0 | Jankx 2.0 |
---|---|---|
Layout System | PHP Classes (Card, Grid, Carousel) | Gutenberg Patterns |
Rendering | Template Engine | Dynamic Query Loop |
Data Storage | Serialized layout data | Block attributes |
Editor Support | Custom admin interface | Gutenberg editor |
Performance | Static rendering | Dynamic with caching |
Migration Process
Phase 1: Analysis and Planning
1.1 Audit Existing Content
function jankx_audit_existing_layouts() {
global $wpdb;
// Find posts with Jankx 1.0 layout shortcodes
$posts_with_layouts = $wpdb->get_results("
SELECT ID, post_content
FROM {$wpdb->posts}
WHERE post_content LIKE '%[jankx/layout%'
");
$layout_usage = [];
foreach ($posts_with_layouts as $post) {
// Extract layout information
preg_match_all('/\[jankx/layout([^\]]*)\](.*?)\[\/jankx/layout\]/s', $post->post_content, $matches);
foreach ($matches[1] as $index => $attributes) {
$attrs = shortcode_parse_atts($attributes);
$layout_type = $attrs['type'] ?? 'card';
if (!isset($layout_usage[$layout_type])) {
$layout_usage[$layout_type] = 0;
}
$layout_usage[$layout_type]++;
}
}
return $layout_usage;
}
1.2 Layout Mapping
$layout_migration_map = [
// Basic layouts
'card' => 'jankx/post-card',
'card-meta' => 'jankx/post-card-meta',
'hero' => 'jankx/hero-post',
// Grid layouts
'grid-2' => 'jankx/grid-2-columns',
'grid-3' => 'jankx/grid-3-columns',
'grid-4' => 'jankx/grid-4-columns',
// Advanced layouts
'carousel' => 'jankx/carousel-basic',
'tabs' => 'jankx/tabs-basic',
'masonry' => 'jankx/masonry-grid',
// Custom layouts
'testimonial' => 'jankx/testimonial-card',
'product' => 'jankx/product-card',
'event' => 'jankx/event-card',
];
Phase 2: Data Migration
2.1 Convert Layout Attributes
function jankx_convert_layout_attributes($old_attributes) {
$new_attributes = [
'postType' => $old_attributes['post_type'] ?? 'post',
'perPage' => $old_attributes['posts_per_page'] ?? 6,
'orderBy' => $old_attributes['orderby'] ?? 'date',
'order' => $old_attributes['order'] ?? 'DESC',
'layoutPattern' => jankx_map_layout_type($old_attributes['type'] ?? 'card'),
'gridColumns' => $old_attributes['columns'] ?? 3,
'showPagination' => !empty($old_attributes['pagination']),
'paginationType' => $old_attributes['pagination_type'] ?? 'numbers',
];
// Handle taxonomy filtering
if (!empty($old_attributes['taxonomy']) && !empty($old_attributes['terms'])) {
$new_attributes['taxonomy'] = $old_attributes['taxonomy'];
$new_attributes['terms'] = explode(',', $old_attributes['terms']);
}
// Handle custom query
if (!empty($old_attributes['custom_query'])) {
$new_attributes['customQuery'] = $old_attributes['custom_query'];
}
return $new_attributes;
}
2.2 Migration Helper Class
class Jankx_Layout_Migration {
private $migration_map;
private $converted_posts = [];
public function __construct() {
$this->migration_map = $this->get_migration_map();
}
public function migrate_post($post_id) {
$post = get_post($post_id);
$content = $post->post_content;
// Find and replace layout shortcodes
$pattern = '/\[jankx_layout([^\]]*)\](.*?)\[\/jankx_layout\]/s';
$new_content = preg_replace_callback($pattern, function($matches) {
return $this->convert_shortcode_to_block($matches[1], $matches[2]);
}, $content);
// Update post content
if ($new_content !== $content) {
wp_update_post([
'ID' => $post_id,
'post_content' => $new_content
]);
$this->converted_posts[] = $post_id;
}
return $new_content;
}
private function convert_shortcode_to_block($attributes_string, $inner_content) {
$attributes = shortcode_parse_atts($attributes_string);
$new_attributes = $this->convert_attributes($attributes);
return $this->render_query_loop_block($new_attributes);
}
private function render_query_loop_block($attributes) {
$block_content = '<!-- wp:jankx/dynamic-query-loop ';
$block_content .= json_encode($attributes);
$block_content .= ' -->';
$block_content .= '<div class="wp-block-jankx-dynamic-query-loop">';
$block_content .= '</div>';
$block_content .= '<!-- /wp:jankx/dynamic-query-loop -->';
return $block_content;
}
public function get_migration_report() {
return [
'total_converted' => count($this->converted_posts),
'converted_posts' => $this->converted_posts,
'migration_map' => $this->migration_map,
];
}
}
Phase 3: Content Migration
3.1 Batch Migration Script
function jankx_batch_migrate_layouts() {
global $wpdb;
// Get all posts with Jankx 1.0 layouts
$posts_to_migrate = $wpdb->get_results("
SELECT ID, post_title, post_content
FROM {$wpdb->posts}
WHERE post_content LIKE '%[jankx/layout%'
AND post_status = 'publish'
");
$migration = new Jankx_Layout_Migration();
$results = [
'success' => 0,
'failed' => 0,
'errors' => [],
];
foreach ($posts_to_migrate as $post) {
try {
$migration->migrate_post($post->ID);
$results['success']++;
} catch (Exception $e) {
$results['failed']++;
$results['errors'][] = [
'post_id' => $post->ID,
'post_title' => $post->post_title,
'error' => $e->getMessage(),
];
}
}
return $results;
}
3.2 Migration Validation
function jankx_validate_migration($post_id) {
$post = get_post($post_id);
$content = $post->post_content;
$validation_results = [
'has_old_shortcodes' => false,
'has_new_blocks' => false,
'block_count' => 0,
'errors' => [],
];
// Check for old shortcodes
if (strpos($content, '[jankx/layout') !== false) {
$validation_results['has_old_shortcodes'] = true;
$validation_results['errors'][] = 'Contains old Jankx 1.0 shortcodes';
}
// Check for new blocks
if (strpos($content, 'jankx/dynamic-query-loop') !== false) {
$validation_results['has_new_blocks'] = true;
// Count blocks
preg_match_all('/<!-- wp:jankx\/dynamic-query-loop/', $content, $matches);
$validation_results['block_count'] = count($matches[0]);
}
return $validation_results;
}
Phase 4: Testing and Validation
4.1 Migration Testing
function jankx_test_migration() {
// Create test post with old layout
$test_post_id = wp_insert_post([
'post_title' => 'Migration Test Post',
'post_content' => '[jankx_layout type="card" posts_per_page="3" columns="2"]Test content[/jankx_layout]',
'post_status' => 'publish',
]);
// Perform migration
$migration = new Jankx_Layout_Migration();
$migrated_content = $migration->migrate_post($test_post_id);
// Validate migration
$validation = jankx_validate_migration($test_post_id);
// Clean up test post
wp_delete_post($test_post_id, true);
return [
'original_content' => get_post($test_post_id)->post_content,
'migrated_content' => $migrated_content,
'validation' => $validation,
];
}
4.2 Rollback Strategy
function jankx_create_migration_backup() {
global $wpdb;
$backup_table = $wpdb->prefix . 'jankx_layout_backup';
// Create backup table
$wpdb->query("
CREATE TABLE IF NOT EXISTS {$backup_table} (
id bigint(20) NOT NULL AUTO_INCREMENT,
post_id bigint(20) NOT NULL,
original_content longtext NOT NULL,
migration_date datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY post_id (post_id)
)
");
// Backup posts with old layouts
$posts_to_backup = $wpdb->get_results("
SELECT ID, post_content
FROM {$wpdb->posts}
WHERE post_content LIKE '%[jankx/layout%'
");
foreach ($posts_to_backup as $post) {
$wpdb->insert($backup_table, [
'post_id' => $post->ID,
'original_content' => $post->post_content,
]);
}
return count($posts_to_backup);
}
Migration Tools
1. Migration Dashboard
function jankx_migration_dashboard() {
?>
<div class="wrap">
<h1>Jankx Layout Migration</h1>
<div class="jankx-migration-status">
<h2>Migration Status</h2>
<?php
$audit_results = jankx_audit_existing_layouts();
$total_posts = array_sum($audit_results);
?>
<p>Found <?php echo $total_posts; ?> posts with Jankx 1.0 layouts</p>
<ul>
<?php foreach ($audit_results as $layout_type => $count): ?>
<li><?php echo ucfirst($layout_type); ?>: <?php echo $count; ?> posts</li>
<?php endforeach; ?>
</ul>
</div>
<div class="jankx-migration-actions">
<h2>Migration Actions</h2>
<form method="post" action="">
<?php wp_nonce_field('jankx_migration', 'jankx_migration_nonce'); ?>
<p>
<button type="submit" name="action" value="create_backup" class="button">
Create Backup
</button>
<button type="submit" name="action" value="test_migration" class="button">
Test Migration
</button>
<button type="submit" name="action" value="start_migration" class="button button-primary">
Start Migration
</button>
</p>
</form>
</div>
<div class="jankx-migration-results">
<h2>Migration Results</h2>
<?php
if (isset($_POST['action']) && wp_verify_nonce($_POST['jankx_migration_nonce'], 'jankx_migration')) {
switch ($_POST['action']) {
case 'create_backup':
$backup_count = jankx_create_migration_backup();
echo '<div class="notice notice-success"><p>Backup created for ' . $backup_count . ' posts.</p></div>';
break;
case 'test_migration':
$test_results = jankx_test_migration();
echo '<div class="notice notice-info"><p>Test migration completed. Check results below.</p></div>';
echo '<pre>' . print_r($test_results, true) . '</pre>';
break;
case 'start_migration':
$migration_results = jankx_batch_migrate_layouts();
echo '<div class="notice notice-success"><p>Migration completed: ' . $migration_results['success'] . ' successful, ' . $migration_results['failed'] . ' failed.</p></div>';
break;
}
}
?>
</div>
</div>
<?php
}
2. Migration CLI Commands
// WP-CLI commands for migration
if (defined('WP_CLI') && WP_CLI) {
WP_CLI::add_command('jankx migrate-layouts', function($args, $assoc_args) {
WP_CLI::log('Starting Jankx layout migration...');
$migration = new Jankx_Layout_Migration();
$results = jankx_batch_migrate_layouts();
WP_CLI::success("Migration completed: {$results['success']} successful, {$results['failed']} failed");
if (!empty($results['errors'])) {
WP_CLI::warning('Some migrations failed:');
foreach ($results['errors'] as $error) {
WP_CLI::log("- Post {$error['post_id']}: {$error['error']}");
}
}
});
WP_CLI::add_command('jankx test-migration', function($args, $assoc_args) {
WP_CLI::log('Testing Jankx layout migration...');
$test_results = jankx_test_migration();
WP_CLI::log('Test results:');
WP_CLI::log(print_r($test_results, true));
});
}
Post-Migration Checklist
1. Content Verification
- All old shortcodes have been converted to blocks
- New blocks render correctly in editor
- New blocks render correctly on frontend
- No broken links or missing content
2. Functionality Testing
- Query loops display correct posts
- Pagination works correctly
- Filters and sorting work
- Responsive design works
- Performance is acceptable
3. User Experience
- Editor interface is intuitive
- Patterns are easy to customize
- Migration didn’t break user workflows
- New features are discoverable
4. Performance Optimization
- Implement caching for dynamic queries
- Optimize database queries
- Minimize asset loading
- Test with large datasets
Troubleshooting
Common Issues
1. Shortcodes Not Converting
// Check if shortcode pattern is correct
function jankx_debug_shortcode_pattern() {
global $wpdb;
$posts = $wpdb->get_results("
SELECT ID, post_content
FROM {$wpdb->posts}
WHERE post_content LIKE '%jankx_layout%'
LIMIT 5
");
foreach ($posts as $post) {
preg_match_all('/\[jankx_layout([^\]]*)\]/', $post->post_content, $matches);
echo "Post {$post->ID}: " . count($matches[0]) . " shortcodes found\n";
}
}
2. Block Rendering Issues
// Check block registration
function jankx_debug_block_registration() {
$blocks = WP_Block_Type_Registry::get_instance()->get_all_registered();
foreach ($blocks as $name => $block) {
if (strpos($name, 'jankx') !== false) {
echo "Block: {$name}\n";
echo "Attributes: " . print_r($block->attributes, true) . "\n";
}
}
}
3. Performance Issues
// Monitor query performance
function jankx_monitor_query_performance() {
global $wpdb;
$start_time = microtime(true);
// Your query here
$query = new WP_Query(['post_type' => 'post', 'posts_per_page' => 10]);
$end_time = microtime(true);
$execution_time = $end_time - $start_time;
error_log("Jankx query execution time: {$execution_time} seconds");
return $execution_time;
}
Best Practices
1. Migration Planning
- Test thoroughly before production migration
- Create backups of all content
- Migrate in phases for large sites
- Monitor performance during migration
2. Content Preservation
- Preserve user customizations during migration
- Maintain SEO-friendly URLs and structure
- Keep metadata intact (custom fields, etc.)
- Document all changes for future reference
3. User Communication
- Notify users about upcoming changes
- Provide training on new interface
- Offer support during transition period
- Gather feedback for improvements
4. Performance Optimization
- Implement caching for dynamic queries
- Optimize database queries for large datasets
- Use lazy loading for images and content
- Monitor server resources during migration