@@ -2260,19 +2260,22 @@ function limitConcurrency(maxConcurrency: number) {
22602260}
22612261const limit = limitConcurrency ( 5 ) ;
22622262
2263- async function featuredImageMapping ( postid : string , post : any , postdata : any ) {
2263+ async function featuredImageMapping ( postid : string , post : any , postdata : any , assetsSchemaPath : string ) {
22642264 try {
2265- const filePath = path . join ( process . cwd ( ) , assetsSave , MIGRATION_DATA_CONFIG . ASSETS_SCHEMA_FILE ) ;
2266- const fileContent = fs . readFileSync ( filePath , 'utf8' ) . trim ( ) ;
2265+ // **THE FIX: Use the path argument directly, don't use the global variable**
2266+ const fileContent = fs . readFileSync ( assetsSchemaPath , 'utf8' ) . trim ( ) ;
22672267
2268- if ( ! fileContent ) {
2269- throw new Error ( `File ${ filePath } is empty or missing` ) ;
2270- }
2271- const assetsId = JSON ?. parse ( fileContent ) ;
2272- if ( ! post [ "wp:postmeta" ] || ! assetsId ) return ;
2268+ if ( ! fileContent ) {
2269+ // File is empty, so no assets have been processed. Nothing to map.
2270+ return postdata ;
2271+ }
22732272
2274- const postmetaArray = Array . isArray ( post [ "wp:postmeta" ] ) ? post [ "wp:postmeta" ]
2275- : [ post [ "wp:postmeta" ] ] ;
2273+ const assetsId = JSON . parse ( fileContent ) ;
2274+ if ( ! post [ "wp:postmeta" ] || ! assetsId ) {
2275+ return postdata ;
2276+ }
2277+
2278+ const postmetaArray = Array . isArray ( post [ "wp:postmeta" ] ) ? post [ "wp:postmeta" ] : [ post [ "wp:postmeta" ] ] ;
22762279
22772280 const assetsDetails = postmetaArray
22782281 . filter ( ( meta ) => meta [ "wp:meta_key" ] === "_thumbnail_id" )
@@ -2283,14 +2286,17 @@ async function featuredImageMapping(postid: string, post: any, postdata: any) {
22832286 ( asset : any ) => asset . uid === attachmentid
22842287 ) ;
22852288 } )
2286- . filter ( Boolean ) ; // Filter out undefined matches
2289+ . filter ( Boolean ) ;
22872290
2288- if ( assetsDetails ?. length > 0 ) {
2291+ if ( assetsDetails . length > 0 && postdata [ postid ] ) {
2292+ // Assign the found asset object to the 'featured_image' field
22892293 postdata [ postid ] [ "featured_image" ] = assetsDetails [ 0 ] ;
22902294 }
22912295 return postdata ;
22922296 } catch ( error ) {
2293- console . error ( error ) ;
2297+ console . error ( "Error during featured image mapping:" , error ) ;
2298+ // Return the original postdata if an error occurs to avoid losing the entry
2299+ return postdata ;
22942300 }
22952301}
22962302
@@ -2383,96 +2389,67 @@ async function processChunkData(
23832389 isLastChunk : boolean ,
23842390 contenttype : any ,
23852391 authorsFilePath : string ,
2386- referencesFilePath : string
2392+ referencesFilePath : string ,
2393+ assetsSchemaPath : string
23872394) {
2388- const postdata : any = { } ;
2389- const formattedPosts : any = { } ;
2390- let postdataCombined = { } ;
2395+ let postdataCombined : Record < string , any > = { } ;
23912396
23922397 try {
2393- const writePromises = [ ] ;
2398+ // This filter is good, it correctly selects only post-like items.
2399+ const filteredChunk = chunkData ?. filter ( ( item : any ) =>
2400+ item [ "wp:post_type" ] !== "page" &&
2401+ item [ "wp:post_type" ] !== "attachment" &&
2402+ [ "publish" , "inherit" , "draft" ] ?. includes ( item [ "wp:status" ] )
2403+ ) ;
23942404
2395- const filteredChunk = chunkData ?. filter ( ( item : any ) => item [ "wp:post_type" ] === "post" && [ "publish" , "inherit" , "draft" ] ?. includes ( item [ "wp:status" ] ) ) ;
2405+ // The main loop processes one item at a time.
23962406 for ( const data of filteredChunk ) {
2397- writePromises . push (
2398- limit ( async ( ) => {
2399- const { postCategories, postTags, postTerms } = extractPostCategories ( data [ "category" ] , referencesFilePath ) ;
2400-
2401-
2402- // Extract author
2403- const postAuthor = extractPostAuthor ( data [ "dc:creator" ] , authorsFilePath ) ;
2404-
2405- const dom = new JSDOM (
2406- data [ "content:encoded" ]
2407- . replace ( / < ! - - .* ?- - > / g, "" )
2408- . replace ( / & l t ; ! - - ? \s + \/ ? w p : .* ?- - & g t ; / g, "" ) ,
2409- { virtualConsole }
2410- ) ;
2411- const htmlDoc = dom . window . document . querySelector ( "body" ) ;
2412- const jsonValue = htmlToJson ( htmlDoc ) ;
2413-
2414- // Format date safely
2415- let postDate : string | null = null ;
2416- try {
2417- const parsed = new Date ( data [ "wp:post_date_gmt" ] ) ;
2418- if ( ! isNaN ( parsed . getTime ( ) ) ) {
2419- postDate = parsed . toISOString ( ) ;
2420- }
2421- } catch ( error ) {
2422- console . error ( `Error parsing date for post ${ data [ "wp:post_id" ] } :` , error ) ;
2423- }
2424-
2425- const base = blog_base_url ?. split ( "/" ) ?. filter ( Boolean ) ;
2426- const blogname = base [ base ?. length - 1 ] ;
2427- const url = data [ "link" ] ?. split ( blogname ) [ 1 ] ;
2428- const uid = `posts_${ data [ "wp:post_id" ] } ` ;
2429- const customId = idCorrector ( uid ) ;
2430-
2431- postdata [ customId ] = {
2432- title : data [ "title" ] || `Posts - ${ data [ "wp:post_id" ] } ` ,
2433- uid : customId ,
2434- url : url ,
2435- date : postDate ,
2436- full_description : jsonValue ,
2437- excerpt : ( data [ "excerpt:encoded" ] || "" )
2438- . replace ( / < ! - - .* ?- - > / g, "" )
2439- . replace ( / & l t ; ! - - ? \s + \/ ? w p : .* ?- - & g t ; / g, "" ) ,
2440- author : postAuthor ,
2441- category : postCategories ,
2442- terms : postTerms ,
2443- tag : postTags ,
2444- featured_image : '' ,
2445- publish_details : [ ] ,
2446- } ;
2447-
2448- for ( const [ key , value ] of Object . entries ( postdata as { [ key : string ] : any } ) ) {
2449- const customId = idCorrector ( value ?. uid ) ;
2450- formattedPosts [ customId ] = {
2451- ...formattedPosts [ customId ] ,
2452- uid : customId ,
2453- ...( await mapContentTypeToEntry ( contenttype , value ) ) ,
2454- } ;
2455- formattedPosts [ customId ] . publish_details = [ ] ;
2456- }
2407+ const customId = idCorrector ( `posts_${ data [ "wp:post_id" ] } ` ) ;
2408+
2409+ // Step 1: Resolve all references for the CURRENT post
2410+ const { postCategories, postTags, postTerms } = extractPostCategories ( data [ "category" ] , referencesFilePath ) ;
2411+ const postAuthor = extractPostAuthor ( data [ "dc:creator" ] , authorsFilePath ) ;
2412+ const jsonValue = htmlToJson ( new JSDOM ( data [ "content:encoded" ] . replace ( "//g" , "" ) . replace ( / & l t ; ! - - ? \s + \/ ? w p : .* ?- - & g t ; / g, "" ) ) . window . document . querySelector ( "body" ) ) ;
2413+ let postDate = null ;
2414+ if ( data [ "wp:post_date_gmt" ] && ! data [ "wp:post_date_gmt" ] . startsWith ( "0000" ) ) {
2415+ postDate = new Date ( data [ "wp:post_date_gmt" ] ) . toISOString ( ) ;
2416+ }
24572417
2458- const formattedPostsWithImage = await featuredImageMapping (
2459- `posts_${ data [ "wp:post_id" ] } ` ,
2460- data ,
2461- formattedPosts
2462- ) ;
2418+ // Step 2: Create a temporary object with all raw data for the CURRENT post
2419+ const rawPostData = {
2420+ title : data [ "title" ] || `Posts - ${ data [ "wp:post_id" ] } ` ,
2421+ uid : customId ,
2422+ url : data [ "link" ] ?. split ( blog_base_url ?. split ( "/" ) . filter ( Boolean ) . pop ( ) ) [ 1 ] ,
2423+ date : postDate ,
2424+ full_description : jsonValue ,
2425+ excerpt : ( data [ "excerpt:encoded" ] || "" ) . replace ( "//g" , "" ) . replace ( / & l t ; ! - - ? \s + \/ ? w p : .* ?- - & g t ; / g, "" ) ,
2426+ author : postAuthor ,
2427+ category : postCategories ,
2428+ terms : postTerms ,
2429+ tag : postTags ,
2430+ featured_image : '' ,
2431+ publish_details : [ ] ,
2432+ } ;
2433+
2434+ // Step 3: Create the final, formatted post object using mapContentTypeToEntry
2435+ let formattedPost = {
2436+ uid : customId ,
2437+ ...( await mapContentTypeToEntry ( contenttype , rawPostData ) ) ,
2438+ publish_details : [ ] ,
2439+ } ;
24632440
2464- postdataCombined = { ...postdataCombined , ...formattedPostsWithImage } ;
2465- } )
2441+ // Step 4: Map the featured image for ONLY the CURRENT post
2442+ const formattedPostWithImage = await featuredImageMapping (
2443+ customId , // Use the corrected ID
2444+ data ,
2445+ { [ customId ] : formattedPost } , // Pass an object with only the current post
2446+ assetsSchemaPath
24662447 ) ;
2467- }
2468-
2469- const results : any = await Promise . all ( writePromises ) ;
2470- const allSuccess = results . every (
2471- ( result : any ) => typeof result !== "object" || result ?. success
2472- ) ;
2473-
2474- if ( isLastChunk && allSuccess ) {
2475- console . info ( "last data" ) ;
2448+
2449+ // Step 5: Add the final, complete post to the combined results
2450+ if ( formattedPostWithImage && formattedPostWithImage [ customId ] ) {
2451+ postdataCombined [ customId ] = formattedPostWithImage [ customId ] ;
2452+ }
24762453 }
24772454
24782455 return postdataCombined ;
@@ -2498,6 +2475,9 @@ async function extractPosts( packagePath: string, destinationStackId: string, pr
24982475 referencesFolder = path . join ( MIGRATION_DATA_CONFIG . DATA , destinationStackId , MIGRATION_DATA_CONFIG . REFERENCES_DIR_NAME ) ;
24992476 const referencesFilePath = path . join ( referencesFolder , MIGRATION_DATA_CONFIG . REFERENCES_FILE_NAME ) ;
25002477
2478+ assetsSave = path . join ( MIGRATION_DATA_CONFIG . DATA , destinationStackId , MIGRATION_DATA_CONFIG . ASSETS_DIR_NAME ) ;
2479+ const assetsSchemaPath = path . join ( assetsSave , MIGRATION_DATA_CONFIG . ASSETS_SCHEMA_FILE ) ;
2480+
25012481 const alldata : any = await fs . promises . readFile ( packagePath , "utf8" ) ;
25022482 const alldataParsed = JSON . parse ( alldata ) ;
25032483 blog_base_url =
@@ -2515,7 +2495,7 @@ async function extractPosts( packagePath: string, destinationStackId: string, pr
25152495 const chunkData = JSON . parse ( data ) ;
25162496 const isLastChunk = filename === lastChunk ;
25172497
2518- const chunkPostData = await processChunkData ( chunkData , filename , isLastChunk , contenttype , authorsFilePath , referencesFilePath ) ;
2498+ const chunkPostData = await processChunkData ( chunkData , filename , isLastChunk , contenttype , authorsFilePath , referencesFilePath , assetsSchemaPath ) ;
25192499 postdataCombined = { ...postdataCombined , ...chunkPostData } ;
25202500
25212501 const seenTitles = new Map ( ) ;
@@ -2656,7 +2636,8 @@ const extractPageParent = (parentId?: string): any[] => {
26562636async function handlePagesChunkData (
26572637 items : any [ ] ,
26582638 contenttype : any ,
2659- authorsFilePath : string
2639+ authorsFilePath : string ,
2640+ assetsSchemaPath : string
26602641) : Promise < Record < string , any > > {
26612642 const pageDataCombined : Record < string , any > = { } ;
26622643
@@ -2666,18 +2647,16 @@ async function handlePagesChunkData(
26662647
26672648 for ( const item of items ) {
26682649 if ( ! allowedPageTypes . includes ( item [ 'wp:post_type' ] ) || ! allowedStatuses . includes ( item [ 'wp:status' ] ) ) {
2669- continue ; // Skip items that aren't valid pages
2650+ continue ;
26702651 }
26712652
26722653 const uid = `pages_${ item [ 'wp:post_id' ] } ` ;
26732654 const customId = idCorrector ( uid ) ;
26742655
2675- // 1. Resolve references for the current item
26762656 const authorRef = extractPageAuthor ( item [ 'dc:creator' ] , authorsFilePath ) ;
26772657 const parentRef = extractPageParent ( item [ 'wp:post_parent' ] ) ;
26782658 const body = htmlToJson ( new JSDOM ( item [ "content:encoded" ] . replace ( "//g" , "" ) . replace ( / & l t ; ! - - ? \s + \/ ? w p : .* ?- - & g t ; / g, "" ) ) . window . document . querySelector ( 'body' ) ) ;
26792659
2680- // 2. Create a temporary object with all the raw data
26812660 const rawPageData = {
26822661 uid : customId ,
26832662 title : item [ 'title' ] || 'Untitled' ,
@@ -2701,9 +2680,10 @@ async function handlePagesChunkData(
27012680
27022681
27032682 const formattedPageWithImage = await featuredImageMapping (
2704- `pages_ ${ item [ "wp:post_id" ] } ` ,
2683+ customId ,
27052684 item ,
2706- { [ customId ] : formattedPage }
2685+ { [ customId ] : formattedPage } ,
2686+ assetsSchemaPath
27072687 ) ;
27082688
27092689
@@ -2743,6 +2723,8 @@ async function extractPages(
27432723 await startingDirPages ( ct , master_locale , project ?. locales ) ;
27442724 const authorsCtName = keyMapper ?. [ "authors" ] || MIGRATION_DATA_CONFIG . AUTHORS_DIR_NAME ;
27452725 const authorsFilePath = path . join ( entrySave , authorsCtName , master_locale , `${ master_locale } .json` ) ;
2726+ assetsSave = path . join ( MIGRATION_DATA_CONFIG . DATA , destinationStackId , MIGRATION_DATA_CONFIG . ASSETS_DIR_NAME ) ;
2727+ const assetsSchemaPath = path . join ( assetsSave , MIGRATION_DATA_CONFIG . ASSETS_SCHEMA_FILE ) ;
27462728 const alldata : any = await fs . promises . readFile ( packagePath , "utf8" ) ;
27472729 const alldataParsed = JSON . parse ( alldata ) ;
27482730 blog_base_url =
@@ -2765,7 +2747,7 @@ async function extractPages(
27652747
27662748 const isLastChunk = filename === lastChunk ;
27672749
2768- const chunkPages = await handlePagesChunkData ( chunkData , contenttype , authorsFilePath ) ;
2750+ const chunkPages = await handlePagesChunkData ( chunkData , contenttype , authorsFilePath , assetsSchemaPath ) ;
27692751
27702752 console . info (
27712753 `${ filename } → Mapped entries: ${ Object . keys ( chunkPages ) . length } `
0 commit comments