gallery-widget.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. /**
  3. * Migration from Jetpack's Gallery Widget to WordPress' Core Gallery Widget.
  4. *
  5. * @since 5.5
  6. *
  7. * @package Jetpack
  8. */
  9. /**
  10. * Migrates all active instances of Jetpack's Gallery widget to Core's Media Gallery widget.
  11. */
  12. function jetpack_migrate_gallery_widget() {
  13. // Only trigger the migration from wp-admin and outside unit tests
  14. if ( ! is_admin() || defined( 'PHPUNIT_JETPACK_TESTSUITE' ) ) {
  15. return;
  16. }
  17. // Only migrate if the new widget is available and we haven't yet migrated
  18. if ( ! class_exists( 'WP_Widget_Media_Gallery' ) || Jetpack_Options::get_option( 'gallery_widget_migration' ) ) {
  19. return;
  20. }
  21. $old_widgets = get_option( 'widget_gallery', array() );
  22. $media_gallery = get_option( 'widget_media_gallery', array() );
  23. $sidebars_widgets = wp_get_sidebars_widgets();
  24. // Array to store legacy widget ids in to unregister on success.
  25. $widgets_to_unregister = array();
  26. $old_widgets = array_filter( $old_widgets, 'jetpack_migrate_gallery_widget_is_importable' );
  27. foreach ( $old_widgets as $id => $widget ) {
  28. $new_id = $id;
  29. // Try to get an unique id for the new type of widget.
  30. // It may be the case that the user has already created a core Gallery Widget
  31. // before the migration begins. (Maybe Jetpack was deactivated during core's upgrade).
  32. for( $i = 0; $i < 10 && in_array( $new_id, array_keys( $media_gallery ) ); $i++, $new_id++ );
  33. $widget_copy = jetpack_migrate_gallery_widget_upgrade_widget( $widget );
  34. if ( null === $widget_copy ) {
  35. jetpack_migrate_gallery_widget_bump_stats( 'gallery-widget-skipped' );
  36. continue;
  37. }
  38. $media_gallery[ $new_id ] = $widget_copy;
  39. $sidebars_widgets = jetpack_migrate_gallery_widget_update_sidebars( $sidebars_widgets, $id, $new_id );
  40. $widgets_to_unregister[ $id ] = $new_id;
  41. }
  42. if ( update_option( 'widget_media_gallery', $media_gallery ) ) {
  43. // Now un-register old widgets and register new.
  44. foreach ( $widgets_to_unregister as $id => $new_id ) {
  45. wp_unregister_sidebar_widget( "gallery-${id}" );
  46. // register new widget.
  47. $media_gallery_widget = new WP_Widget_Media_Gallery();
  48. $media_gallery_widget->_set( $new_id );
  49. $media_gallery_widget->_register_one( $new_id );
  50. }
  51. wp_set_sidebars_widgets( $sidebars_widgets );
  52. // Log if we migrated all, or some for this site.
  53. foreach ( $widgets_to_unregister as $w ) {
  54. jetpack_migrate_gallery_widget_bump_stats( 'gallery-widget-migrated' );
  55. }
  56. // We need to refresh on widgets page for changes to take effect.
  57. // The jetpack_refresh_on_widget_page function is already defined in migrate-to-core/image-widget.php
  58. add_action( 'current_screen', 'jetpack_refresh_on_widget_page' );
  59. }
  60. Jetpack_Options::update_option( 'gallery_widget_migration', true );
  61. }
  62. function jetpack_migrate_gallery_widget_is_importable( $widget ) {
  63. // Can be caused by instantiating but not populating a widget in the Customizer.
  64. if ( empty( $widget ) ) {
  65. return false;
  66. }
  67. // The array as stored in the option constains two keys and one
  68. // is a string `_multiwidget` which does not represent a widget, so we skip it
  69. if ( ! is_array( $widget ) ) {
  70. return false;
  71. }
  72. return true;
  73. }
  74. /**
  75. * Returns a transformed version of the Gallery Widget.
  76. * Will return null if the widget is either empty, is not an array or has more keys than expected
  77. *
  78. * @param $widget One of the Jetpack Gallery widgets to be transformed into a new Core Media Gallery Widget
  79. *
  80. * @return array|null
  81. */
  82. function jetpack_migrate_gallery_widget_upgrade_widget( $widget ) {
  83. $whitelisted_keys = array(
  84. 'ids' => '',
  85. 'link' => '',
  86. 'title' => '',
  87. 'type' => '',
  88. 'random' => '',
  89. 'conditions' => '',
  90. );
  91. $default_data = array(
  92. 'columns' => 3,
  93. 'ids' => array(),
  94. 'link_type' => '',
  95. 'orderby_random' => false,
  96. 'size' => 'thumbnail',
  97. 'title' => '',
  98. 'type' => '',
  99. );
  100. if ( ! jetpack_migrate_gallery_widget_is_importable( $widget ) ) {
  101. return null;
  102. }
  103. // Ensure widget has no keys other than those expected.
  104. // Not all widgets have conditions, so lets add it in.
  105. $widget_copy = array_merge( array( 'conditions' => null ), $widget );
  106. $non_whitelisted_keys = array_diff_key( $widget_copy, $whitelisted_keys );
  107. if ( count( $non_whitelisted_keys ) > 0 ) {
  108. jetpack_migrate_gallery_widget_bump_stats( 'extra-key' );
  109. // Log the names of the keys not in our whitelist.
  110. foreach ( $non_whitelisted_keys as $key => $value ) {
  111. jetpack_migrate_gallery_widget_bump_stats( "extra-key-$key", "migration-extra-key" );
  112. }
  113. }
  114. $widget_copy = array_merge( $default_data, $widget, array(
  115. // ids in Jetpack's Gallery are a string of comma-separated values.
  116. // Core's Media Gallery Widget stores ids in an array
  117. 'ids' => explode( ',', $widget['ids'] ),
  118. 'link_type' => $widget['link'],
  119. 'orderby_random' => isset( $widget['random'] ) && $widget['random'] === 'on',
  120. ) );
  121. // Unsetting old widget fields
  122. $widget_copy = array_diff_key( $widget_copy, array(
  123. 'link' => false,
  124. 'random' => false,
  125. ) );
  126. return $widget_copy;
  127. }
  128. /**
  129. * Replaces the references to Jetpack Gallery Widget in the sidebars for references to the new version of the widget
  130. *
  131. * @param $sidebars_widgets The sidebar widgets array to update
  132. * @param $id Old id of the widget (basically its index in the array )
  133. * @param $new_id New id that will be using on the sidebar as a new widget
  134. *
  135. * @return mixed Updated sidebar widgets array
  136. */
  137. function jetpack_migrate_gallery_widget_update_sidebars( $sidebars_widgets, $id, $new_id ) {
  138. foreach ( $sidebars_widgets as $sidebar => $widgets ) {
  139. if (
  140. is_array( $widgets )
  141. && false !== ( $key = array_search( "gallery-{$id}", $widgets, true ) )
  142. ) {
  143. $sidebars_widgets[ $sidebar ][ $key ] = "media_gallery-{$new_id}";
  144. // Check if the inactive widgets sidebar exists
  145. // Related: https://core.trac.wordpress.org/ticket/14893
  146. if ( ! isset( $sidebars_widgets['wp_inactive_widgets'] ) || ! is_array( $sidebars_widgets['wp_inactive_widgets'] ) ) {
  147. $sidebars_widgets['wp_inactive_widgets'] = array();
  148. }
  149. $sidebars_widgets['wp_inactive_widgets'][ $key ] = "gallery-{$id}";
  150. }
  151. }
  152. return $sidebars_widgets;
  153. }
  154. /**
  155. * Will bump stat in jetpack_gallery_widget_migration group.
  156. *
  157. * @param string $bin The bin to log into.
  158. * @param string $group The group name. Defaults to "widget-migration".
  159. */
  160. function jetpack_migrate_gallery_widget_bump_stats( $bin, $group = 'widget-migration' ) {
  161. // If this is being run on .com bumps_stats_extra exists, but using the filter looks more elegant.
  162. if ( function_exists( 'bump_stats_extras' ) ) {
  163. $group = "jetpack-$group";
  164. do_action( 'jetpack_bump_stats_extra', $group, $bin );
  165. } else {
  166. // $group is prepended with 'jetpack-'
  167. $jetpack = Jetpack::init();
  168. $jetpack->stat( $group, $bin ) ;
  169. }
  170. }
  171. add_action( 'widgets_init', 'jetpack_migrate_gallery_widget' );