@caweb/cli 1.11.1 → 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,6 +28,9 @@ import {
28
28
  promptForSync,
29
29
  promptForId
30
30
  } from './prompts.js';
31
+ import { get } from 'http';
32
+ import { connect } from 'http2';
33
+ import { create } from 'domain';
31
34
 
32
35
  const errors = [];
33
36
  const configFile = path.join(appPath, 'caweb.json');
@@ -95,7 +98,7 @@ async function getInstanceInfo( config, instance = 'target'){
95
98
  config = config ?? {};
96
99
 
97
100
  // add the target to sync list
98
- config.sync[nickname] = target;
101
+ config['sync'][nickname] = target;
99
102
 
100
103
  fs.writeFileSync(
101
104
  configFile,
@@ -107,6 +110,53 @@ async function getInstanceInfo( config, instance = 'target'){
107
110
  }
108
111
  }
109
112
 
113
+ /**
114
+ *
115
+ * @param {*} navJson
116
+ * @param {*} destUrl
117
+ * @returns {Array}
118
+ */
119
+ function getStaticNavItems(navJson, destUrl){
120
+ let navItems = [];
121
+
122
+ // iterate over the nav items
123
+ for( let item of navJson ){
124
+ let i = {
125
+ title: item.label,
126
+ url: item.url
127
+ }
128
+
129
+ if( item.description ){
130
+ i.description = item.description;
131
+ }
132
+
133
+ // if the item url is not the same as the destination url
134
+ // and is not relative, then the item is an external link
135
+ // if( item.url !== destUrl && ! item.url.startsWith('/') ){
136
+ // navItems.push(i)
137
+ // }else
138
+ if( item.url.startsWith('/') ){
139
+ // we remove the forward slash and the file extension if applicable
140
+ i.slug = item.url.replace(/^\//, '').replace(/\.[^/.]+$/, '');
141
+ i.url = `${destUrl}/${i.slug}`;
142
+ i.type = 'post_type';
143
+ i.object = 'page';
144
+ }
145
+
146
+ // if there is a submenu
147
+ if( item.sub && item.sub.length ){
148
+ i.sub = getStaticNavItems(item.sub, destUrl);
149
+ }
150
+
151
+
152
+ navItems.push(i)
153
+
154
+ }
155
+
156
+ return navItems;
157
+
158
+ }
159
+
110
160
  /**
111
161
  * Sync Environments.
112
162
  *
@@ -137,11 +187,10 @@ export default async function sync({
137
187
  const {workDirectoryPath} = await loadConfig(path.resolve('.'));
138
188
 
139
189
  // read caweb configuration file.
140
- let serviceConfig = fs.existsSync(configFile) ? JSON.parse( fs.readFileSync(configFile) ) : { "sync": {} };
190
+ let serviceConfig = fs.existsSync(configFile) ? JSON.parse( fs.readFileSync(configFile) ) : { sync: {} };
141
191
 
142
192
  process.env.WP_CLI_CONFIG_PATH = path.join(workDirectoryPath, 'config.yml');
143
193
 
144
- // get target and dest instance data
145
194
  target = serviceConfig.sync[target];
146
195
  dest = serviceConfig.sync[dest];
147
196
 
@@ -158,7 +207,6 @@ export default async function sync({
158
207
  }
159
208
  }
160
209
 
161
-
162
210
  // if no dest was specified or no dest saved.
163
211
  if( ! dest ){
164
212
  spinner.stop()
@@ -179,7 +227,7 @@ export default async function sync({
179
227
  ! target || ! target.url || ! target.user || ! target.pwd ||
180
228
  ! dest || ! dest.url || ! dest.user || ! dest.pwd
181
229
  ){
182
- spinner.fail(`caweb.json is not configured properly for ${target} and ${dest}.`);
230
+ spinner.fail(`caweb.json is not configured properly.`);
183
231
  process.exit(1)
184
232
  }
185
233
 
@@ -209,7 +257,7 @@ export default async function sync({
209
257
  * 5) We only collect menus if the taxonomy is undefined or it's set to menus.
210
258
  * - We also collect menu items if menus are collected.
211
259
  */
212
- let settings = [];
260
+ let settings = [{}];
213
261
  let mediaLibrary = [];
214
262
  let media = [];
215
263
  let pages = [];
@@ -242,274 +290,374 @@ export default async function sync({
242
290
 
243
291
  }
244
292
 
245
- // Media Library.
246
- if( tax.includes('media', 'pages', 'posts') ){
247
- spinner.text = `Collecting Media Library ${target.url}`;
248
- mediaLibrary = await getTaxonomies({
249
- ...targetOptions,
250
- fields: [
251
- 'id',
252
- 'source_url',
253
- 'title',
254
- 'caption',
255
- 'alt_text',
256
- 'date',
257
- 'mime_type',
258
- 'post',
259
- 'media_details'
260
- ],
261
- include: mediaIds && mediaIds.length ? mediaIds.join(',') : null
262
- },
263
- 'media',
264
- debug
265
- );
266
- }
293
+ // if the request is going from static,
294
+ // we create a taxonomies object based off of the static data.
295
+ if( 'static' === target.url ){
296
+ let mediaPath = serviceConfig.media;
297
+
298
+ // iterate over pages and create a pages object.
299
+ for( let page of serviceConfig.pages ){
300
+ let content = page.shortcodeContent.replace('\"', '"');
301
+
302
+ pages.push({
303
+ title: page.title,
304
+ status: 'publish',
305
+ slug: page.slug,
306
+ content,
307
+ meta: {
308
+ _et_pb_use_builder: 'on', // this turns on the Divi Builder
309
+ }
310
+ })
311
+ }
267
312
 
268
- // Site Settings.
269
- if( tax.includes('settings') ){
270
- spinner.text = `Collecting Site Settings from ${target.url}`;
271
- settings = await getTaxonomies({
272
- ...targetOptions,
273
- fields: [
274
- 'title',
275
- 'description',
276
- 'show_on_front',
277
- 'page_on_front',
278
- 'posts_per_page'
279
- ],
280
- }, 'settings', debug )
281
-
282
- }
313
+ // Header Nav
314
+ if( serviceConfig?.site?.header?.nav ){
315
+ menus.push({
316
+ name: 'Header Menu',
317
+ slug: 'header-menu',
318
+ locations: 'header-menu',
319
+ });
283
320
 
284
- // Pages.
285
- if( tax.includes('pages') ){
286
- // get all pages/posts
287
- spinner.text = `Collecting pages from ${target.url}`;
288
- pages = await getTaxonomies({
289
- ...targetOptions,
290
- orderby: 'parent',
291
- embed: true,
292
- include: pageIds && pageIds.length ? pageIds.join(',') : null
293
- },
294
- 'pages',
295
- debug
296
- );
321
+ menuNavItems['header'] = getStaticNavItems(serviceConfig.site.header.nav, destOptions.url);
297
322
 
298
- // pages can be nested so we have to collect any parent items.
299
- pages = await getParentItems(
300
- pages,
301
- targetOptions,
302
- 'pages',
303
- debug
304
- )
305
- }
323
+ }
306
324
 
307
- // Posts.
308
- if( tax.includes('posts') ){
309
- // get all pages/posts
310
- spinner.text = `Collecting all posts from ${target.url}`;
311
- posts = await getTaxonomies({
312
- ...targetOptions,
313
- orderby: 'parent',
314
- include: postIds && postIds.length ? postIds.join(',') : null
315
- },
316
- 'posts',
317
- debug
318
- );
319
-
320
- // posts can be nested so we have to collect any parent items.
321
- posts = await getParentItems(
322
- posts,
323
- targetOptions,
324
- 'posts',
325
- debug
326
- )
327
- }
325
+ // Footer Nav
326
+ if( serviceConfig?.site?.footer?.nav ){
327
+ menus.push({
328
+ name: 'Footer Menu',
329
+ slug: 'footer-menu',
330
+ locations: 'footer-menu',
331
+ });
328
332
 
329
- /**
330
- * Media Library Handling
331
- *
332
- * We iterate thru the media library to identify which media should be synced.
333
- * 1) attached media items by default are only possible on pages.
334
- * 2) featured media by default are only possible on posts.
335
- * 3) save any linked media in the content of pages and posts.
336
- */
337
- for( let m of mediaLibrary ){
338
- // remove any new line characters.
339
- m.source_url = m.source_url.replace('\n','');
333
+ menuNavItems['footer'] = getStaticNavItems(serviceConfig.site.footer.nav, destOptions.url);
340
334
 
341
- /**
342
- * We collect the media if:
343
- * - media is attached
344
- * - id was explicitly requested
345
- * - tax includes media and media ids is blank
346
- */
347
- if(
348
- m.post ||
349
- ( mediaIds && mediaIds.includes( m.id.toString() ) ) ||
350
- ( tax.includes('media') && undefined === mediaIds )
351
- ){
352
- media.push( m );
353
-
354
- // we don't have to check any further.
355
- continue;
356
335
  }
357
336
 
358
- for( let p of [].concat( pages, posts ) ){
359
- /**
360
- * We collect the media if:
361
- * - media is featured image
362
- * - media is the src attribute in the content
363
- */
364
- if( p.featured_media === m.id ||
365
- p.content.rendered.match( new RegExp(`src=”(${m.source_url}.*)”`, 'g') )){
366
- media.push( m );
367
- }
368
- }
369
- }
337
+ // if the media path exists
338
+ if( fs.existsSync(mediaPath) ){
339
+ let currentDate = new Date();
340
+ let uploadDir = path.join(
341
+ 'wp-content', 'uploads',
342
+ currentDate.getFullYear().toString(), (currentDate.getMonth() + 1).toString().padStart(2, '0')
343
+ );
370
344
 
371
- // filter any duplicate media.
372
- media = media.filter((m, index, self) => { return index === self.findIndex((t) => { return t.id === m.id; })} );
373
- let i = 0;
374
-
375
- // before we can upload media files we have to generate the media blob data.
376
- for( let m of media ){
377
- if( debug ){
378
- i++;
379
- spinner.info(`Media ID ${m.id} Collected: ${i}/${media.length}`)
345
+ // we read all the files in the media directory and create a media object.
346
+ fs.readdirSync(mediaPath, {recursive: true}).forEach( (file) => {
347
+
348
+ // update page content file references
349
+ pages.forEach((page) => {
350
+ // if the page content includes the file, we replace it the WordPress site upload dir.
351
+ if( page.content && page.content.includes(file) ){
352
+ // unescape slashes added from path.join.
353
+ page.content = page.content.replace(
354
+ new RegExp(`"[\\S]*${file}`, 'g'),
355
+ `"${destOptions.url}/` + path.join(uploadDir, file).replace(/\\/g, '/')
356
+ );
357
+
358
+ }
359
+ })
360
+
361
+ // if the file is a file, we read it and create a media object.
362
+ let filePath = path.join(mediaPath, file);
363
+
364
+ if( fs.statSync(filePath).isFile() ){
365
+ // read the file and create a media object.
366
+ let mediaBlob = fs.readFileSync(filePath);
367
+
368
+ // and new media object
369
+ media.push({
370
+ source_url: filePath,
371
+ title: path.basename(filePath).replace(/\.[^/.]+$/, ""),
372
+ alt_text: path.basename(filePath).replace(/\.[^/.]+$/, ""),
373
+ media_details:{},
374
+ date: currentDate.toISOString(),
375
+ data: new Blob([mediaBlob])
376
+ });
377
+ }
378
+ })
380
379
  }
381
380
 
382
- const mediaBlob = await axios.request(
383
- {
384
- ...targetOptions,
385
- url: m.source_url,
386
- responseType: 'arraybuffer'
387
- }
388
- )
389
- .then( (img) => { return new Blob([img.data]) })
390
- .catch( (error) => {
391
- errors.push(`${m.source_url} could not be downloaded.`)
392
- return false;
393
- });
394
-
395
- if( mediaBlob ){
396
- m.data = mediaBlob;
381
+ // Settings
382
+ settings[0] = {
383
+ title: serviceConfig?.site?.title,
397
384
  }
398
- }
399
-
400
- // this has to be done after we have the media data.
401
- // Lets replace the url references in the content of the pages and posts.
402
- for( let p of [].concat( pages, posts ) ){
403
- p.content.rendered = p.content.rendered.replace( new RegExp(target.url, 'g'), dest.url );
404
- }
405
385
 
406
- // Menu and Nav Items.
407
- if( tax.includes('menus')){
408
- spinner.text = `Collecting assigned navigation menus from ${target.url}`;
409
- // get all menus and navigation links
410
- menus = await getTaxonomies({
411
- ...targetOptions,
412
- fields: [
413
- 'id',
414
- 'description',
415
- 'name',
416
- 'slug',
417
- 'meta',
418
- 'locations'
419
- ],
420
- include: menuIds && menuIds.length ? menuIds.join(',') : null
421
- }, 'menus', debug);
422
-
423
- menuNavItems = await getTaxonomies(
424
- {
386
+ }else{
387
+
388
+ // Media Library.
389
+ if( tax.includes('media', 'pages', 'posts') ){
390
+ spinner.text = `Collecting Media Library ${target.url}`;
391
+ mediaLibrary = await getTaxonomies({
392
+ ...targetOptions,
393
+ fields: [
394
+ 'id',
395
+ 'source_url',
396
+ 'title',
397
+ 'caption',
398
+ 'alt_text',
399
+ 'date',
400
+ 'mime_type',
401
+ 'post',
402
+ 'media_details'
403
+ ],
404
+ include: mediaIds && mediaIds.length ? mediaIds.join(',') : null
405
+ },
406
+ 'media',
407
+ debug
408
+ );
409
+ }
410
+
411
+ // Site Settings.
412
+ if( tax.includes('settings') ){
413
+ spinner.text = `Collecting Site Settings from ${target.url}`;
414
+ settings = await getTaxonomies({
425
415
  ...targetOptions,
426
416
  fields: [
427
- 'id',
428
417
  'title',
429
- 'url',
430
- 'status',
431
- 'attr_title',
432
418
  'description',
433
- 'type',
434
- 'type_label',
435
- 'object',
436
- 'object_id',
437
- 'parent',
438
- 'menu_order',
439
- 'target',
440
- 'classes',
441
- 'xfn',
442
- 'meta',
443
- 'menus'
419
+ 'show_on_front',
420
+ 'page_on_front',
421
+ 'posts_per_page'
444
422
  ],
445
- menus: menus.map((menu) => { return menu.id; })
446
- },
447
- 'menu-items',
448
- debug
449
- )
450
-
451
- let missingPages = [];
452
- let missingPosts = [];
453
- // we iterate over menu items
454
- menuNavItems.forEach(item => {
455
- // if the item is a page and it wasn't previously collected
456
- if( 'page' === item.object && ! pages.map(p => p.id ).includes(item.object_id) ){
457
- missingPages.push(item.object_id)
458
- // if the item is a post and it wasn't previously collected
459
- }else if( 'post' === item.object && ! posts.map(p => p.id ).includes(item.object_id) ){
460
- missingPosts.push(item.object_id)
461
- }
462
- })
463
-
464
- // if navigation pages weren't previously collected they must be collected.
465
- if( missingPages.length ){
466
- missingPages = await getTaxonomies({
467
- ...targetOptions,
468
- orderby: 'parent',
469
- embed: true,
470
- include: missingPages.join(',')
423
+ }, 'settings', debug )
424
+
425
+ }
426
+
427
+ // Pages.
428
+ if( tax.includes('pages') ){
429
+ // get all pages/posts
430
+ spinner.text = `Collecting pages from ${target.url}`;
431
+ pages = await getTaxonomies({
432
+ ...targetOptions,
433
+ orderby: 'parent',
434
+ embed: true,
435
+ include: pageIds && pageIds.length ? pageIds.join(',') : null
471
436
  },
472
437
  'pages',
473
438
  debug
474
439
  );
475
440
 
476
441
  // pages can be nested so we have to collect any parent items.
477
- missingPages = await getParentItems(
478
- missingPages,
442
+ pages = await getParentItems(
443
+ pages,
479
444
  targetOptions,
480
445
  'pages',
481
446
  debug
482
- );
447
+ )
483
448
 
484
- // add the missing pages to the pages array
485
- pages = pages.concat(missingPages)
486
449
  }
487
450
 
488
- // if navigation posts weren't previously collected they must be collected.
489
- if( missingPosts.length ){
451
+ // Posts.
452
+ if( tax.includes('posts') ){
490
453
  // get all pages/posts
491
454
  spinner.text = `Collecting all posts from ${target.url}`;
492
- missingPosts = await getTaxonomies({
455
+ posts = await getTaxonomies({
493
456
  ...targetOptions,
494
457
  orderby: 'parent',
495
- include: missingPosts.join(',')
458
+ include: postIds && postIds.length ? postIds.join(',') : null
496
459
  },
497
- 'posts',
460
+ 'posts',
498
461
  debug
499
462
  );
500
463
 
501
464
  // posts can be nested so we have to collect any parent items.
502
- missingPosts = await getParentItems(
503
- missingPosts,
504
- targetOptions,
505
- 'posts',
506
- debug
465
+ posts = await getParentItems(
466
+ posts,
467
+ targetOptions,
468
+ 'posts',
469
+ debug
470
+ )
471
+ }
472
+
473
+ /**
474
+ * Media Library Handling
475
+ *
476
+ * We iterate thru the media library to identify which media should be synced.
477
+ * 1) attached media items by default are only possible on pages.
478
+ * 2) featured media by default are only possible on posts.
479
+ * 3) save any linked media in the content of pages and posts.
480
+ */
481
+ for( let m of mediaLibrary ){
482
+ // remove any new line characters.
483
+ m.source_url = m.source_url.replace('\n','');
484
+
485
+ /**
486
+ * We collect the media if:
487
+ * - media is attached
488
+ * - id was explicitly requested
489
+ * - tax includes media and media ids is blank
490
+ */
491
+ if(
492
+ m.post ||
493
+ ( mediaIds && mediaIds.includes( m.id.toString() ) ) ||
494
+ ( tax.includes('media') && undefined === mediaIds )
495
+ ){
496
+ media.push( m );
497
+
498
+ // we don't have to check any further.
499
+ continue;
500
+ }
501
+
502
+ for( let p of [].concat( pages, posts ) ){
503
+ /**
504
+ * We collect the media if:
505
+ * - media is featured image
506
+ * - media is the src attribute in the content
507
+ */
508
+ if( p.featured_media === m.id ||
509
+ p.content.rendered.match( new RegExp(`src=”(${m.source_url}.*)”`, 'g') )){
510
+ media.push( m );
511
+ }
512
+ }
513
+ }
514
+
515
+ // filter any duplicate media.
516
+ media = media.filter((m, index, self) => { return index === self.findIndex((t) => { return t.id === m.id; })} );
517
+ let i = 0;
518
+
519
+ // before we can upload media files we have to generate the media blob data.
520
+ for( let m of media ){
521
+ if( debug ){
522
+ i++;
523
+ spinner.info(`Media ID ${m.id} Collected: ${i}/${media.length}`)
524
+ }
525
+
526
+ const mediaBlob = await axios.request(
527
+ {
528
+ ...targetOptions,
529
+ url: m.source_url,
530
+ responseType: 'arraybuffer'
531
+ }
507
532
  )
533
+ .then( (img) => { return new Blob([img.data]) })
534
+ .catch( (error) => {
535
+ errors.push(`${m.source_url} could not be downloaded.`)
536
+ return false;
537
+ });
508
538
 
509
- // add the missing posts to the posts array
510
- posts = posts.concat(missingPages);
539
+ if( mediaBlob ){
540
+ m.data = mediaBlob;
541
+ }
542
+ }
543
+
544
+ // this has to be done after we have the media data.
545
+ // Lets replace the url references in the content of the pages and posts.
546
+ for( let p of [].concat( pages, posts ) ){
547
+ if( p.content.rendered ){
548
+ p.content.rendered = p.content.rendered.replace( new RegExp(target.url, 'g'), dest.url );
549
+ }
550
+ }
551
+
552
+ // Menu and Nav Items.
553
+ if( tax.includes('menus')){
554
+ spinner.text = `Collecting assigned navigation menus from ${target.url}`;
555
+ // get all menus and navigation links
556
+ menus = await getTaxonomies({
557
+ ...targetOptions,
558
+ fields: [
559
+ 'id',
560
+ 'description',
561
+ 'name',
562
+ 'slug',
563
+ 'meta',
564
+ 'locations'
565
+ ],
566
+ include: menuIds && menuIds.length ? menuIds.join(',') : null
567
+ }, 'menus', debug);
568
+
569
+ menuNavItems = await getTaxonomies(
570
+ {
571
+ ...targetOptions,
572
+ fields: [
573
+ 'id',
574
+ 'title',
575
+ 'url',
576
+ 'status',
577
+ 'attr_title',
578
+ 'description',
579
+ 'type',
580
+ 'type_label',
581
+ 'object',
582
+ 'object_id',
583
+ 'parent',
584
+ 'menu_order',
585
+ 'target',
586
+ 'classes',
587
+ 'xfn',
588
+ 'meta',
589
+ 'menus'
590
+ ],
591
+ menus: menus.map((menu) => { return menu.id; })
592
+ },
593
+ 'menu-items',
594
+ debug
595
+ )
596
+
597
+ let missingPages = [];
598
+ let missingPosts = [];
599
+ // we iterate over menu items
600
+ menuNavItems.forEach(item => {
601
+ // if the item is a page and it wasn't previously collected
602
+ if( 'page' === item.object && ! pages.map(p => p.id ).includes(item.object_id) ){
603
+ missingPages.push(item.object_id)
604
+ // if the item is a post and it wasn't previously collected
605
+ }else if( 'post' === item.object && ! posts.map(p => p.id ).includes(item.object_id) ){
606
+ missingPosts.push(item.object_id)
607
+ }
608
+ })
609
+
610
+ // if navigation pages weren't previously collected they must be collected.
611
+ if( missingPages.length ){
612
+ missingPages = await getTaxonomies({
613
+ ...targetOptions,
614
+ orderby: 'parent',
615
+ embed: true,
616
+ include: missingPages.join(',')
617
+ },
618
+ 'pages',
619
+ debug
620
+ );
621
+
622
+ // pages can be nested so we have to collect any parent items.
623
+ missingPages = await getParentItems(
624
+ missingPages,
625
+ targetOptions,
626
+ 'pages',
627
+ debug
628
+ );
629
+
630
+ // add the missing pages to the pages array
631
+ pages = pages.concat(missingPages)
632
+ }
633
+
634
+ // if navigation posts weren't previously collected they must be collected.
635
+ if( missingPosts.length ){
636
+ // get all pages/posts
637
+ spinner.text = `Collecting all posts from ${target.url}`;
638
+ missingPosts = await getTaxonomies({
639
+ ...targetOptions,
640
+ orderby: 'parent',
641
+ include: missingPosts.join(',')
642
+ },
643
+ 'posts',
644
+ debug
645
+ );
646
+
647
+ // posts can be nested so we have to collect any parent items.
648
+ missingPosts = await getParentItems(
649
+ missingPosts,
650
+ targetOptions,
651
+ 'posts',
652
+ debug
653
+ )
654
+
655
+ // add the missing posts to the posts array
656
+ posts = posts.concat(missingPages);
657
+ }
511
658
  }
512
659
  }
660
+
513
661
 
514
662
  /**
515
663
  * Now we have all the data we can begin to create the taxonomies on the target.
@@ -534,9 +682,10 @@ export default async function sync({
534
682
  }
535
683
 
536
684
  // Pages.
685
+ let createdPages = [];
537
686
  if( pages ){
538
687
  spinner.text = `Creating all pages to ${dest.url}`;
539
- await createTaxonomies( pages, destOptions, 'pages', spinner );
688
+ createdPages = await createTaxonomies( pages, destOptions, 'pages', spinner );
540
689
  }
541
690
 
542
691
  // Posts.
@@ -548,14 +697,115 @@ export default async function sync({
548
697
  // Menus and Navigation Links.
549
698
  if( menus ){
550
699
  spinner.text = `Reconstructing navigation menus to ${dest.url}`;
551
- await createTaxonomies(menus, destOptions, 'menus', spinner);
552
- await createTaxonomies(menuNavItems, destOptions, 'menu-items', spinner);
700
+ let createdMenus = await createTaxonomies(menus, destOptions, 'menus', spinner);
701
+
702
+ // this variable is only used if the request is going from static
703
+ // we initialize it here outside of the if statement
704
+ // since we need to assign the ids of the created menu items to the sub menu items.
705
+ let subMenus = [];
706
+
707
+ // only if the request is going from static
708
+ if( 'static' === target.url ){
709
+ let headerMenu = createdMenus.find((menu) => { return menu.slug === 'header-menu'; }) || {};
710
+ let footerMenu = createdMenus.find((menu) => { return menu.slug === 'footer-menu'; }) || {};
711
+
712
+ /**
713
+ * Modify menu items.
714
+ *
715
+ * We iterate over the menu items and delete certain properties.
716
+ * We also assign the menu id to the menu items.
717
+ * We also assign the page id to the menu items if they have a slug.
718
+ *
719
+ */
720
+ Object.entries(menuNavItems).forEach(([key, value]) => {
721
+ let menuId = 'header' === key ? headerMenu?.id : footerMenu?.id;
722
+
723
+ // if the required menu is not created, we delete the menu item
724
+ if( ! menuId ){
725
+ delete menuNavItems[key];
726
+ return;
727
+ }
728
+
729
+ value.forEach((v, k) => {
730
+ // assign the newly created menu ids to the menu items
731
+ v.menus = menuId;
732
+
733
+ // if the item has a slug we update the url and remove the slug property
734
+ if( v.slug ){
735
+ // find the page id
736
+ let pageId = createdPages.find((p) => { return p.slug === v.slug; })?.id;
737
+
738
+ v.object_id = pageId;
739
+
740
+ delete v.slug;
741
+ }
742
+
743
+ // if the item has sub items we have to assign the sub items to the parent item
744
+ if( v.sub ){
745
+ v.sub.forEach((subItem, subIndex) => {
746
+ subItem.menus = menuId;
747
+
748
+ // if the item has a slug we update the url and remove the slug property
749
+ if( subItem.slug ){
750
+ // find the page id
751
+ let subPageId = createdPages.find((p) => { return p.slug === subItem.slug; })?.id;
752
+
753
+ subItem.object_id = subPageId;
754
+
755
+ delete subItem.slug;
756
+ }
757
+ })
758
+
759
+ subMenus[k] = v.sub;
760
+
761
+ delete v.sub;
762
+ }
763
+ })
764
+
765
+ // this ensures that the array contains only the menu items
766
+ // we add the value back to the menuNavItems
767
+ // delete the key from the menuNavItems
768
+ menuNavItems = [
769
+ ...menuNavItems,
770
+ ...value
771
+ ]
772
+
773
+ delete menuNavItems[key];
774
+ })
775
+ }
776
+
777
+ let createdMenuItems = await createTaxonomies(menuNavItems, destOptions, 'menu-items', spinner);
778
+
779
+ // if we have sub menus, we have to create them as well.
780
+ if( subMenus && subMenus.length ){
781
+ // we iterate over the sub menus and assign the parent id to the sub menu items
782
+ subMenus.forEach((sub, index) => {
783
+ sub.forEach((s) => {
784
+ s.parent = createdMenuItems[index].id;
785
+ s.menu_order = index;
786
+ })
787
+ })
788
+
789
+ // now we can create the sub menus
790
+ await createTaxonomies(subMenus.filter( i => i).flat(), destOptions, 'menu-items', spinner);
791
+ }
553
792
  }
554
793
 
555
794
 
556
795
  // Settings.
557
796
  if( settings ){
558
797
  spinner.text = `Updating site settings to ${dest.url}`;
798
+
799
+ // if going from static, we have to set the homepage and posts page.
800
+ if( 'static' === target.url ){
801
+ let homepageID = createdPages.find((p) => { return 'index' === p.slug; })?.id || 0;
802
+
803
+ if( homepageID ){
804
+ settings[0]['page_on_front'] = homepageID;
805
+ settings[0]['show_on_front'] = 'page';
806
+ }
807
+ }
808
+
559
809
  await createTaxonomies(settings, destOptions, 'settings', spinner);
560
810
  }
561
811