fix: don't import special entries that are not posts or pages

This commit is contained in:
2026-02-14 22:51:18 +01:00
parent 33a94d41c2
commit 58b46c9229
3 changed files with 217 additions and 3 deletions

View File

@@ -267,10 +267,16 @@ export class ImportExecutionEngine extends EventEmitter {
options: ImportExecutionOptions, options: ImportExecutionOptions,
progress: (phase: string, current: number, total: number, detail?: string) => void progress: (phase: string, current: number, total: number, detail?: string) => void
): Promise<void> { ): Promise<void> {
const total = report.posts.items.length; // Filter to only actual posts (postType === 'post'), skip nav_menu_item, revision, etc.
const postsToImport = report.posts.items.filter(item => item.wxrPost.postType === 'post');
const total = postsToImport.length;
for (let i = 0; i < report.posts.items.length; i++) { // Count skipped "other" post types
const analyzed = report.posts.items[i]; const skippedOther = report.posts.items.length - postsToImport.length;
result.posts.skipped += skippedOther;
for (let i = 0; i < postsToImport.length; i++) {
const analyzed = postsToImport[i];
progress('posts', i + 1, total, `Processing: ${analyzed.wxrPost.title}`); progress('posts', i + 1, total, `Processing: ${analyzed.wxrPost.title}`);
try { try {

View File

@@ -45,6 +45,11 @@
6. PAGE IMPORT 6. PAGE IMPORT
- Page ID 501: Standard page → becomes post with "page" category - Page ID 501: Standard page → becomes post with "page" category
- Page ID 502: Page with HTML content for conversion test - Page ID 502: Page with HTML content for conversion test
7. OTHER POST TYPES (should be analyzed but NOT imported)
- Post ID 601: nav_menu_item → analyzed but skipped
- Post ID 602: revision → analyzed but skipped
- Post ID 603: wp_template → analyzed but skipped
--> -->
<rss version="2.0" <rss version="2.0"
xmlns:excerpt="http://wordpress.org/export/1.2/excerpt/" xmlns:excerpt="http://wordpress.org/export/1.2/excerpt/"
@@ -604,5 +609,66 @@ with multiple lines</pre>]]></content:encoded>
<wp:post_parent>0</wp:post_parent> <wp:post_parent>0</wp:post_parent>
</item> </item>
<!-- ======================================== -->
<!-- SECTION 7: OTHER POST TYPES -->
<!-- (Analyzed but NOT imported by executor) -->
<!-- ======================================== -->
<!-- Post 601: Navigation menu item -->
<item>
<title>Home Menu Link</title>
<link>https://testblog.example.com/home-menu/</link>
<pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
<dc:creator><![CDATA[admin]]></dc:creator>
<content:encoded><![CDATA[]]></content:encoded>
<wp:post_id>601</wp:post_id>
<wp:post_date>2024-01-01 00:00:00</wp:post_date>
<wp:post_date_gmt>2024-01-01 00:00:00</wp:post_date_gmt>
<wp:post_modified>2024-01-01 00:00:00</wp:post_modified>
<wp:post_modified_gmt>2024-01-01 00:00:00</wp:post_modified_gmt>
<wp:post_name>home-menu-link</wp:post_name>
<wp:status>publish</wp:status>
<wp:post_type>nav_menu_item</wp:post_type>
<wp:post_parent>0</wp:post_parent>
</item>
<!-- Post 602: Post revision -->
<item>
<title>HTML Formatting Test: Basic Text Styles (Revision)</title>
<link>https://testblog.example.com/?p=602</link>
<pubDate>Mon, 01 Jan 2024 09:00:00 +0000</pubDate>
<dc:creator><![CDATA[testauthor]]></dc:creator>
<content:encoded><![CDATA[<p>Old revision content that should be ignored.</p>]]></content:encoded>
<wp:post_id>602</wp:post_id>
<wp:post_date>2024-01-01 09:00:00</wp:post_date>
<wp:post_date_gmt>2024-01-01 09:00:00</wp:post_date_gmt>
<wp:post_modified>2024-01-01 09:00:00</wp:post_modified>
<wp:post_modified_gmt>2024-01-01 09:00:00</wp:post_modified_gmt>
<wp:post_name>101-revision-v1</wp:post_name>
<wp:status>inherit</wp:status>
<wp:post_type>revision</wp:post_type>
<wp:post_parent>101</wp:post_parent>
</item>
<!-- Post 603: Block template -->
<item>
<title>Single Post Template</title>
<link>https://testblog.example.com/wp_template/single/</link>
<pubDate>Tue, 02 Jan 2024 00:00:00 +0000</pubDate>
<dc:creator><![CDATA[admin]]></dc:creator>
<content:encoded><![CDATA[<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:post-content /-->
<!-- wp:template-part {"slug":"footer"} /-->]]></content:encoded>
<wp:post_id>603</wp:post_id>
<wp:post_date>2024-01-02 00:00:00</wp:post_date>
<wp:post_date_gmt>2024-01-02 00:00:00</wp:post_date_gmt>
<wp:post_modified>2024-01-02 00:00:00</wp:post_modified>
<wp:post_modified_gmt>2024-01-02 00:00:00</wp:post_modified_gmt>
<wp:post_name>single</wp:post_name>
<wp:status>publish</wp:status>
<wp:post_type>wp_template</wp:post_type>
<wp:post_parent>0</wp:post_parent>
</item>
</channel> </channel>
</rss> </rss>

View File

@@ -11,6 +11,7 @@
* 4. Conflict Resolution - verifies ignore/overwrite/import behaviors * 4. Conflict Resolution - verifies ignore/overwrite/import behaviors
* 5. Media Import - verifies media file handling with post linkage * 5. Media Import - verifies media file handling with post linkage
* 6. Page Import - verifies pages become posts with "page" category * 6. Page Import - verifies pages become posts with "page" category
* 7. Other Post Types - verifies nav_menu_item, revision, wp_template are analyzed but not imported
*/ */
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
@@ -1375,4 +1376,145 @@ describe('ImportExecutionEngine E2E Tests', () => {
expect(result.wpIdToPostId.size).toBeGreaterThanOrEqual(2); // post1, post3 expect(result.wpIdToPostId.size).toBeGreaterThanOrEqual(2); // post1, post3
}); });
}); });
// ==========================================================================
// SECTION 7: OTHER POST TYPES (analyzed but not imported)
// ==========================================================================
describe('Other Post Types (analyzed but not imported)', () => {
it('should include nav_menu_item, revision, and wp_template in WXR parsed data', () => {
// Verify the WXR parser includes these in the posts array
const navMenuItem = wxrData.posts.find(p => p.wpId === 601);
const revision = wxrData.posts.find(p => p.wpId === 602);
const wpTemplate = wxrData.posts.find(p => p.wpId === 603);
expect(navMenuItem).toBeDefined();
expect(navMenuItem!.postType).toBe('nav_menu_item');
expect(navMenuItem!.title).toBe('Home Menu Link');
expect(revision).toBeDefined();
expect(revision!.postType).toBe('revision');
expect(revision!.slug).toBe('101-revision-v1');
expect(wpTemplate).toBeDefined();
expect(wpTemplate!.postType).toBe('wp_template');
expect(wpTemplate!.title).toBe('Single Post Template');
});
it('should include other post types in analysis report but skip them during import', async () => {
// Find the "other" post types from parsed WXR
const navMenuItem = wxrData.posts.find(p => p.wpId === 601)!;
const revision = wxrData.posts.find(p => p.wpId === 602)!;
const wpTemplate = wxrData.posts.find(p => p.wpId === 603)!;
// Also include a regular post to verify it gets imported
const regularPost = wxrData.posts.find(p => p.wpId === 101)!;
// Create analysis report that includes both regular posts and "other" post types
const report: ImportAnalysisReport = {
wxrData: wxrData,
posts: {
total: 4,
new: 4,
update: 0,
conflict: 0,
items: [
{
wxrPost: regularPost,
status: 'new' as PostAnalysisStatus,
contentHash: 'hash1',
markdownPreview: '',
},
{
wxrPost: navMenuItem,
status: 'new' as PostAnalysisStatus,
contentHash: 'hash2',
markdownPreview: '',
},
{
wxrPost: revision,
status: 'new' as PostAnalysisStatus,
contentHash: 'hash3',
markdownPreview: '',
},
{
wxrPost: wpTemplate,
status: 'new' as PostAnalysisStatus,
contentHash: 'hash4',
markdownPreview: '',
},
],
},
pages: { total: 0, new: 0, update: 0, conflict: 0, items: [] },
media: { total: 0, new: 0, update: 0, conflict: 0, missing: 0, items: [] },
tags: [],
categories: [],
site: wxrData.site,
macros: { totalUniqueMacros: 0, totalMacroUsages: 0, allMapped: true, macros: [] },
};
const result = await engine.executeImport(report, {});
// Verify only the regular post was imported
expect(result.posts.imported).toBe(1);
// The 3 "other" post types should be skipped
expect(result.posts.skipped).toBe(3);
expect(result.posts.errors).toBe(0);
// Verify only one post was actually written to database/filesystem
expect(insertedPosts.length).toBe(1);
expect(insertedPosts[0].slug).toBe('html-formatting-basic');
// Verify no files were written for nav_menu_item, revision, or wp_template
const writtenSlugs = writtenFiles.map(f => f.path);
expect(writtenSlugs.some(p => p.includes('home-menu-link'))).toBe(false);
expect(writtenSlugs.some(p => p.includes('101-revision-v1'))).toBe(false);
expect(writtenSlugs.some(p => p.includes('single'))).toBe(false);
});
it('should correctly count skipped "other" types in result summary', async () => {
// Test with only "other" post types to verify counting
const navMenuItem = wxrData.posts.find(p => p.wpId === 601)!;
const revision = wxrData.posts.find(p => p.wpId === 602)!;
const report: ImportAnalysisReport = {
wxrData: wxrData,
posts: {
total: 2,
new: 2,
update: 0,
conflict: 0,
items: [
{
wxrPost: navMenuItem,
status: 'new' as PostAnalysisStatus,
contentHash: 'hash1',
markdownPreview: '',
},
{
wxrPost: revision,
status: 'new' as PostAnalysisStatus,
contentHash: 'hash2',
markdownPreview: '',
},
],
},
pages: { total: 0, new: 0, update: 0, conflict: 0, items: [] },
media: { total: 0, new: 0, update: 0, conflict: 0, missing: 0, items: [] },
tags: [],
categories: [],
site: wxrData.site,
macros: { totalUniqueMacros: 0, totalMacroUsages: 0, allMapped: true, macros: [] },
};
const result = await engine.executeImport(report, {});
// All should be skipped, none imported
expect(result.posts.imported).toBe(0);
expect(result.posts.skipped).toBe(2);
expect(result.posts.errors).toBe(0);
expect(insertedPosts.length).toBe(0);
});
});
}); });