@wordpress/data 6.4.1 → 6.6.1

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { merge, isPlainObject } from 'lodash';
4
+ import { merge, isPlainObject, identity } from 'lodash';
5
5
 
6
6
  /**
7
7
  * Internal dependencies
@@ -252,29 +252,31 @@ export function migrateFeaturePreferencesToPreferencesStore(
252
252
  : sourceFeatures;
253
253
 
254
254
  if ( featuresToMigrate ) {
255
- const targetFeatures = state[ preferencesStoreName ]?.preferences;
255
+ const existingPreferences = state[ preferencesStoreName ]?.preferences;
256
256
 
257
257
  // Avoid migrating features again if they've previously been migrated.
258
- if ( ! targetFeatures?.[ sourceStoreName ] ) {
258
+ if ( ! existingPreferences?.[ sourceStoreName ] ) {
259
259
  // Set the feature values in the interface store, the features
260
260
  // object is keyed by 'scope', which matches the store name for
261
261
  // the source.
262
262
  persistence.set( preferencesStoreName, {
263
263
  preferences: {
264
- ...targetFeatures,
264
+ ...existingPreferences,
265
265
  [ sourceStoreName ]: featuresToMigrate,
266
266
  },
267
267
  } );
268
268
 
269
269
  // Remove migrated feature preferences from `interface`.
270
270
  if ( interfaceFeatures ) {
271
- const otherInterfaceFeatures =
271
+ const otherInterfaceState = state[ interfaceStoreName ];
272
+ const otherInterfaceScopes =
272
273
  state[ interfaceStoreName ]?.preferences?.features;
273
274
 
274
275
  persistence.set( interfaceStoreName, {
276
+ ...otherInterfaceState,
275
277
  preferences: {
276
278
  features: {
277
- ...otherInterfaceFeatures,
279
+ ...otherInterfaceScopes,
278
280
  [ sourceStoreName ]: undefined,
279
281
  },
280
282
  },
@@ -283,9 +285,11 @@ export function migrateFeaturePreferencesToPreferencesStore(
283
285
 
284
286
  // Remove migrated feature preferences from the source.
285
287
  if ( sourceFeatures ) {
288
+ const otherSourceState = state[ sourceStoreName ];
286
289
  const sourcePreferences = state[ sourceStoreName ]?.preferences;
287
290
 
288
291
  persistence.set( sourceStoreName, {
292
+ ...otherSourceState,
289
293
  preferences: {
290
294
  ...sourcePreferences,
291
295
  features: undefined,
@@ -296,47 +300,62 @@ export function migrateFeaturePreferencesToPreferencesStore(
296
300
  }
297
301
  }
298
302
 
303
+ /**
304
+ * Migrates an individual item inside the `preferences` object for a store.
305
+ *
306
+ * @param {Object} persistence The persistence interface.
307
+ * @param {Object} migrate An options object that contains details of the migration.
308
+ * @param {string} migrate.from The name of the store to migrate from.
309
+ * @param {string} migrate.scope The scope in the preferences store to migrate to.
310
+ * @param {string} key The key in the preferences object to migrate.
311
+ * @param {?Function} convert A function that converts preferences from one format to another.
312
+ */
299
313
  export function migrateIndividualPreferenceToPreferencesStore(
300
314
  persistence,
301
- sourceStoreName,
302
- key
315
+ { from: sourceStoreName, scope },
316
+ key,
317
+ convert = identity
303
318
  ) {
304
319
  const preferencesStoreName = 'core/preferences';
305
320
  const state = persistence.get();
306
321
  const sourcePreference = state[ sourceStoreName ]?.preferences?.[ key ];
307
322
 
308
323
  // There's nothing to migrate, exit early.
309
- if ( ! sourcePreference ) {
324
+ if ( sourcePreference === undefined ) {
310
325
  return;
311
326
  }
312
327
 
313
328
  const targetPreference =
314
- state[ preferencesStoreName ]?.preferences?.[ sourceStoreName ]?.[
315
- key
316
- ];
329
+ state[ preferencesStoreName ]?.preferences?.[ scope ]?.[ key ];
317
330
 
318
331
  // There's existing data at the target, so don't overwrite it, exit early.
319
332
  if ( targetPreference ) {
320
333
  return;
321
334
  }
322
335
 
323
- const allPreferences = state[ preferencesStoreName ]?.preferences;
324
- const targetPreferences =
325
- state[ preferencesStoreName ]?.preferences?.[ sourceStoreName ];
336
+ const otherScopes = state[ preferencesStoreName ]?.preferences;
337
+ const otherPreferences =
338
+ state[ preferencesStoreName ]?.preferences?.[ scope ];
339
+
340
+ // Pass an object with the key and value as this allows the convert
341
+ // function to convert to a data structure that has different keys.
342
+ const convertedPreferences = convert( { [ key ]: sourcePreference } );
326
343
 
327
344
  persistence.set( preferencesStoreName, {
328
345
  preferences: {
329
- ...allPreferences,
330
- [ sourceStoreName ]: {
331
- ...targetPreferences,
332
- [ key ]: sourcePreference,
346
+ ...otherScopes,
347
+ [ scope ]: {
348
+ ...otherPreferences,
349
+ ...convertedPreferences,
333
350
  },
334
351
  },
335
352
  } );
336
353
 
337
354
  // Remove migrated feature preferences from the source.
355
+ const otherSourceState = state[ sourceStoreName ];
338
356
  const allSourcePreferences = state[ sourceStoreName ]?.preferences;
339
357
  persistence.set( sourceStoreName, {
358
+ ...otherSourceState,
340
359
  preferences: {
341
360
  ...allSourcePreferences,
342
361
  [ key ]: undefined,
@@ -345,55 +364,231 @@ export function migrateIndividualPreferenceToPreferencesStore(
345
364
  }
346
365
 
347
366
  /**
348
- * Move the 'features' object in local storage from the sourceStoreName to the
349
- * interface store.
367
+ * Convert from:
368
+ * ```
369
+ * {
370
+ * panels: {
371
+ * tags: {
372
+ * enabled: true,
373
+ * opened: true,
374
+ * },
375
+ * permalinks: {
376
+ * enabled: false,
377
+ * opened: false,
378
+ * },
379
+ * },
380
+ * }
381
+ * ```
350
382
  *
351
- * @param {Object} persistence The persistence interface.
352
- * @param {string} sourceStoreName The name of the store that has persisted
353
- * preferences to migrate to the interface
354
- * package.
383
+ * to:
384
+ * {
385
+ * inactivePanels: [
386
+ * 'permalinks',
387
+ * ],
388
+ * openPanels: [
389
+ * 'tags',
390
+ * ],
391
+ * }
392
+ *
393
+ * @param {Object} preferences A preferences object.
394
+ *
395
+ * @return {Object} The converted data.
355
396
  */
356
- export function migrateFeaturePreferencesToInterfaceStore(
357
- persistence,
358
- sourceStoreName
397
+ export function convertEditPostPanels( preferences ) {
398
+ const panels = preferences?.panels ?? {};
399
+ return Object.keys( panels ).reduce(
400
+ ( convertedData, panelName ) => {
401
+ const panel = panels[ panelName ];
402
+
403
+ if ( panel?.enabled === false ) {
404
+ convertedData.inactivePanels.push( panelName );
405
+ }
406
+
407
+ if ( panel?.opened === true ) {
408
+ convertedData.openPanels.push( panelName );
409
+ }
410
+
411
+ return convertedData;
412
+ },
413
+ { inactivePanels: [], openPanels: [] }
414
+ );
415
+ }
416
+
417
+ export function migrateThirdPartyFeaturePreferencesToPreferencesStore(
418
+ persistence
359
419
  ) {
360
420
  const interfaceStoreName = 'core/interface';
361
- const state = persistence.get();
362
- const sourcePreferences = state[ sourceStoreName ]?.preferences;
363
- const sourceFeatures = sourcePreferences?.features;
421
+ const preferencesStoreName = 'core/preferences';
422
+
423
+ let state = persistence.get();
424
+
425
+ const interfaceScopes = state[ interfaceStoreName ]?.preferences?.features;
364
426
 
365
- if ( sourceFeatures ) {
366
- const targetFeatures =
427
+ for ( const scope in interfaceScopes ) {
428
+ // Don't migrate any core 'scopes'.
429
+ if ( scope.startsWith( 'core' ) ) {
430
+ continue;
431
+ }
432
+
433
+ // Skip this scope if there are no features to migrate.
434
+ const featuresToMigrate = interfaceScopes[ scope ];
435
+ if ( ! featuresToMigrate ) {
436
+ continue;
437
+ }
438
+
439
+ const existingPreferences = state[ preferencesStoreName ]?.preferences;
440
+
441
+ // Add the data to the preferences store structure.
442
+ persistence.set( preferencesStoreName, {
443
+ preferences: {
444
+ ...existingPreferences,
445
+ [ scope ]: featuresToMigrate,
446
+ },
447
+ } );
448
+
449
+ // Remove the data from the interface store structure.
450
+ // Call `persistence.get` again to make sure `state` is up-to-date with
451
+ // any changes from the previous iteration of this loop.
452
+ state = persistence.get();
453
+ const otherInterfaceState = state[ interfaceStoreName ];
454
+ const otherInterfaceScopes =
367
455
  state[ interfaceStoreName ]?.preferences?.features;
368
456
 
369
- // Avoid migrating features again if they've previously been migrated.
370
- if ( ! targetFeatures?.[ sourceStoreName ] ) {
371
- // Set the feature values in the interface store, the features
372
- // object is keyed by 'scope', which matches the store name for
373
- // the source.
374
- persistence.set( interfaceStoreName, {
375
- preferences: {
376
- features: {
377
- ...targetFeatures,
378
- [ sourceStoreName ]: sourceFeatures,
379
- },
457
+ persistence.set( interfaceStoreName, {
458
+ ...otherInterfaceState,
459
+ preferences: {
460
+ features: {
461
+ ...otherInterfaceScopes,
462
+ [ scope ]: undefined,
380
463
  },
381
- } );
464
+ },
465
+ } );
466
+ }
467
+ }
382
468
 
383
- // Remove feature preferences from the source.
384
- persistence.set( sourceStoreName, {
385
- preferences: {
386
- ...sourcePreferences,
387
- features: undefined,
388
- },
389
- } );
390
- }
469
+ /**
470
+ * Migrates interface 'enableItems' data to the preferences store.
471
+ *
472
+ * The interface package stores this data in this format:
473
+ * ```js
474
+ * {
475
+ * enableItems: {
476
+ * singleEnableItems: {
477
+ * complementaryArea: {
478
+ * 'core/edit-post': 'edit-post/document',
479
+ * 'core/edit-site': 'edit-site/global-styles',
480
+ * }
481
+ * },
482
+ * multipleEnableItems: {
483
+ * pinnedItems: {
484
+ * 'core/edit-post': {
485
+ * 'plugin-1': true,
486
+ * },
487
+ * 'core/edit-site': {
488
+ * 'plugin-2': true,
489
+ * },
490
+ * },
491
+ * }
492
+ * }
493
+ * }
494
+ * ```
495
+ * and it should be migrated it to:
496
+ * ```js
497
+ * {
498
+ * 'core/edit-post': {
499
+ * complementaryArea: 'edit-post/document',
500
+ * pinnedItems: {
501
+ * 'plugin-1': true,
502
+ * },
503
+ * },
504
+ * 'core/edit-site': {
505
+ * complementaryArea: 'edit-site/global-styles',
506
+ * pinnedItems: {
507
+ * 'plugin-2': true,
508
+ * },
509
+ * },
510
+ * }
511
+ * ```
512
+ *
513
+ * @param {Object} persistence The persistence interface.
514
+ */
515
+ export function migrateInterfaceEnableItemsToPreferencesStore( persistence ) {
516
+ const interfaceStoreName = 'core/interface';
517
+ const preferencesStoreName = 'core/preferences';
518
+ const state = persistence.get();
519
+ const sourceEnableItems = state[ interfaceStoreName ]?.enableItems;
520
+
521
+ // There's nothing to migrate, exit early.
522
+ if ( ! sourceEnableItems ) {
523
+ return;
391
524
  }
525
+
526
+ const allPreferences = state[ preferencesStoreName ]?.preferences ?? {};
527
+
528
+ // First convert complementaryAreas into the right format.
529
+ // Use the existing preferences as the accumulator so that the data is
530
+ // merged.
531
+ const sourceComplementaryAreas =
532
+ sourceEnableItems?.singleEnableItems?.complementaryArea ?? {};
533
+
534
+ const convertedComplementaryAreas = Object.keys(
535
+ sourceComplementaryAreas
536
+ ).reduce( ( accumulator, scope ) => {
537
+ const data = sourceComplementaryAreas[ scope ];
538
+
539
+ // Don't overwrite any existing data in the preferences store.
540
+ if ( accumulator[ scope ]?.complementaryArea ) {
541
+ return accumulator;
542
+ }
543
+
544
+ return {
545
+ ...accumulator,
546
+ [ scope ]: {
547
+ ...accumulator[ scope ],
548
+ complementaryArea: data,
549
+ },
550
+ };
551
+ }, allPreferences );
552
+
553
+ // Next feed the converted complementary areas back into a reducer that
554
+ // converts the pinned items, resulting in the fully migrated data.
555
+ const sourcePinnedItems =
556
+ sourceEnableItems?.multipleEnableItems?.pinnedItems ?? {};
557
+ const allConvertedData = Object.keys( sourcePinnedItems ).reduce(
558
+ ( accumulator, scope ) => {
559
+ const data = sourcePinnedItems[ scope ];
560
+ // Don't overwrite any existing data in the preferences store.
561
+ if ( accumulator[ scope ]?.pinnedItems ) {
562
+ return accumulator;
563
+ }
564
+
565
+ return {
566
+ ...accumulator,
567
+ [ scope ]: {
568
+ ...accumulator[ scope ],
569
+ pinnedItems: data,
570
+ },
571
+ };
572
+ },
573
+ convertedComplementaryAreas
574
+ );
575
+
576
+ persistence.set( preferencesStoreName, {
577
+ preferences: allConvertedData,
578
+ } );
579
+
580
+ // Remove migrated preferences.
581
+ const otherInterfaceItems = state[ interfaceStoreName ];
582
+ persistence.set( interfaceStoreName, {
583
+ ...otherInterfaceItems,
584
+ enableItems: undefined,
585
+ } );
392
586
  }
393
587
 
394
588
  persistencePlugin.__unstableMigrate = ( pluginOptions ) => {
395
589
  const persistence = createPersistenceInterface( pluginOptions );
396
590
 
591
+ // Boolean feature preferences.
397
592
  migrateFeaturePreferencesToPreferencesStore(
398
593
  persistence,
399
594
  'core/edit-widgets'
@@ -406,20 +601,45 @@ persistencePlugin.__unstableMigrate = ( pluginOptions ) => {
406
601
  persistence,
407
602
  'core/edit-post'
408
603
  );
604
+ migrateFeaturePreferencesToPreferencesStore(
605
+ persistence,
606
+ 'core/edit-site'
607
+ );
608
+ migrateThirdPartyFeaturePreferencesToPreferencesStore( persistence );
609
+
610
+ // Other ad-hoc preferences.
409
611
  migrateIndividualPreferenceToPreferencesStore(
410
612
  persistence,
411
- 'core/edit-post',
613
+ { from: 'core/edit-post', scope: 'core/edit-post' },
412
614
  'hiddenBlockTypes'
413
615
  );
414
- migrateFeaturePreferencesToPreferencesStore(
616
+ migrateIndividualPreferenceToPreferencesStore(
415
617
  persistence,
416
- 'core/edit-site'
618
+ { from: 'core/edit-post', scope: 'core/edit-post' },
619
+ 'editorMode'
620
+ );
621
+ migrateIndividualPreferenceToPreferencesStore(
622
+ persistence,
623
+ { from: 'core/edit-post', scope: 'core/edit-post' },
624
+ 'preferredStyleVariations'
625
+ );
626
+ migrateIndividualPreferenceToPreferencesStore(
627
+ persistence,
628
+ { from: 'core/edit-post', scope: 'core/edit-post' },
629
+ 'panels',
630
+ convertEditPostPanels
631
+ );
632
+ migrateIndividualPreferenceToPreferencesStore(
633
+ persistence,
634
+ { from: 'core/editor', scope: 'core/edit-post' },
635
+ 'isPublishSidebarEnabled'
417
636
  );
418
637
  migrateIndividualPreferenceToPreferencesStore(
419
638
  persistence,
420
- 'core/edit-site',
639
+ { from: 'core/edit-site', scope: 'core/edit-site' },
421
640
  'editorMode'
422
641
  );
642
+ migrateInterfaceEnableItemsToPreferencesStore( persistence );
423
643
  };
424
644
 
425
645
  export default persistencePlugin;