diff --git a/.github/changelog/fix-3332-migration-cpt-order b/.github/changelog/fix-3332-migration-cpt-order new file mode 100644 index 0000000000..66c8073ce5 --- /dev/null +++ b/.github/changelog/fix-3332-migration-cpt-order @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Fixed a warning that could appear when the plugin was activated or updated. diff --git a/includes/class-migration.php b/includes/class-migration.php index 39f1d5fef9..1c92d1f9ee 100644 --- a/includes/class-migration.php +++ b/includes/class-migration.php @@ -26,7 +26,15 @@ class Migration { * Initialize the class, registering WordPress hooks. */ public static function init() { - self::maybe_migrate(); + /* + * Priority 15: after `register_extra_fields_post_types` at 11 (so the + * `ap_extrafield` / `ap_extrafield_blog` post types exist when the + * initial migration inserts the default "Powered by" field) and before + * the rewrite flush below at priority 20. If you renumber one, renumber + * the other, a callback added to the same priority bucket during its + * own dispatch does not run for that dispatch. + */ + \add_action( 'init', array( self::class, 'maybe_migrate' ), 15 ); Scheduler::register_async_batch_callback( 'activitypub_migrate_from_0_17', array( self::class, 'migrate_from_0_17' ) ); Scheduler::register_async_batch_callback( 'activitypub_update_comment_counts', array( self::class, 'update_comment_counts' ) ); @@ -226,10 +234,10 @@ public static function maybe_migrate() { } /* - * Defer the flush to late in the `init` cycle (priority 20). Migration::init - * runs at priority 1, which is earlier than most plugins register their - * rewrite rules. Flushing synchronously here would persist a truncated - * ruleset that omits third-party rules added on `init` at priority 10. + * Defer the flush to late in the `init` cycle (priority 20), after the + * priority-10 crowd that registers most plugin rewrite rules. Flushing + * synchronously here would persist a truncated ruleset that omits + * third-party rules added on `init` at priority 10. */ \add_action( 'init', array( Activitypub::class, 'flush_rewrite_rules' ), 20 ); diff --git a/tests/phpunit/tests/includes/class-test-migration.php b/tests/phpunit/tests/includes/class-test-migration.php index 5bfaf2962d..c19117483c 100644 --- a/tests/phpunit/tests/includes/class-test-migration.php +++ b/tests/phpunit/tests/includes/class-test-migration.php @@ -16,6 +16,7 @@ use Activitypub\Collection\Remote_Actors; use Activitypub\Comment; use Activitypub\Migration; +use Activitypub\Post_Types; use Activitypub\Scheduler; use Activitypub\Tombstone; @@ -633,6 +634,33 @@ public function mock_webfinger() { ); } + /** + * Regression guard: Migration::init() must register maybe_migrate() on + * `init` at a priority strictly greater than the priority used by + * Post_Types::register_extra_fields_post_types() (11), so the + * `ap_extrafield` / `ap_extrafield_blog` post types exist when the + * fresh-install migration inserts the default "Powered by" field (see + * #3332). This pins the hook-ordering contract, it does not by itself + * prove the `map_meta_cap` `_doing_it_wrong` notice is gone. + * + * @covers ::init + */ + public function test_init_defers_migration_past_post_type_registration() { + $migration_priority = \has_action( 'init', array( Migration::class, 'maybe_migrate' ) ); + $cpt_registration_callback = array( Post_Types::class, 'register_extra_fields_post_types' ); + $cpt_registration_priority = \has_action( 'init', $cpt_registration_callback ); + + $this->assertNotFalse( $migration_priority, 'Migration::init() must register maybe_migrate() on init.' ); + $this->assertNotFalse( $cpt_registration_priority, 'Extra-fields CPT registration must be hooked on init.' ); + + $this->assertIsInt( $migration_priority, 'maybe_migrate() must be registered with a numeric priority.' ); + $this->assertGreaterThan( + (int) $cpt_registration_priority, + (int) $migration_priority, + 'Migration must run after the extra-fields post types are registered.' + ); + } + /** * Test add_default_extra_field. */