Only seed the "Powered by" profile field once - #3666
Open
pfefferle wants to merge 8 commits into
Open
Conversation
The 'Powered by WordPress' field re-appearing after deletion (issue #3280) isn't a duplicate of the same field — it is Extra_Fields::default_actor_extra_fields spawning Blog/Profile/Homepage replacements once the user's list goes empty. Migration::add_default_extra_field created the Powered-by entry on initial install but never set the activitypub_default_extra_fields flag, so the filter's $already_migrated check never saw it. Deleting the Migration-provisioned entry left the user in a state where the next get_actor_fields() call (during federation, admin UI loads, or Mastodon API responses) triggered the filter, which created a fresh set of unrelated defaults. Setting the flag in add_default_extra_field stops the spawn on new installs. A version-gated backfill (backfill_default_extra_fields_flag) does the same for sites that already went through the initial migration. Fixes #3280
11 tasks
There was a problem hiding this comment.
Pull request overview
This PR fixes repeated seeding of the default “Powered by WordPress” extra field by introducing an explicit provisioning flag (activitypub_default_extra_fields) that is claimed atomically before inserts, and by backfilling that flag for existing installs during migration.
Changes:
- Make
Migration::add_default_extra_field()claim the provisioning flag before inserting, so replayed migrations become no-ops and deletions don’t trigger other defaults. - Add a new migration step
backfill_default_extra_fields_flag()to set the flag for actors that already have extra fields. - Add PHPUnit coverage for “delete stays deleted”, replayed migrations, and backfill behavior; add two changelog entries.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
includes/class-migration.php |
Claims activitypub_default_extra_fields before seeding “Powered by”, and adds a backfill migration for the flag. |
tests/phpunit/tests/includes/class-test-migration.php |
Adds regression tests ensuring deletion doesn’t re-provision defaults and replays don’t reseed. |
.github/changelog/fix-powered-by-flag |
Changelog entry for deletion “sticking” instead of being replaced by other defaults. |
.github/changelog/fix-powered-by-duplicates |
Changelog entry for preventing repeated “Powered by WordPress” insertions. |
Suppressed comments (1)
includes/class-migration.php:823
- For the blog actor, the option flag is claimed with
add_option()and then the post is inserted, but the insert result isn't checked. If the insert fails after the option is set, the blog actor becomes permanently marked as provisioned and later runs won't be able to retry seeding.
'post_content' => $content,
)
);
}
// add_option() only writes when the row does not exist yet, which claims the blog actor the same way.
if ( \add_option( 'activitypub_default_extra_fields', true, '', false ) ) {
\wp_insert_post(
array(
'post_type' => Extra_Fields::BLOG_POST_TYPE,
'post_author' => 0,
'post_status' => 'publish',
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3280
Fixes #3339
Proposed changes:
Two bugs, one missing flag.
Extra_Fields::default_actor_extra_fields()writes anactivitypub_default_extra_fieldsflag when it provisions defaults, and checks that flag before provisioning again.Migration::add_default_extra_field(), the one that adds the "Powered by" entry, never wrote it. So:get_actor_fields()call spawned Blog/Profile/Homepage replacements. That is what people see as the field "reappearing" (**Bug report: "Powered by WordPress" extra field duplicates randomly on post edits** #3280).activitypub_db_versionis only written at the very end ofmaybe_migrate(), so a migration that fails or times out before that replays the whole initial migration and adds another "Powered by" entry. The lock clears itself after 30 minutes, so it can repeat (Powered by WordPress #3339).The fix is to claim the actor with that flag before inserting,
add_user_meta( ..., $unique = true )for users andadd_option()for the blog actor. Both only write when the row does not exist yet, so a replay is a no-op and a field somebody deleted is not seeded again.backfill_default_extra_fields_flag()sets the flag on existing installs. It only marks actors that still hold an extra field, because those were provisioned by an earlier run. Actors with no fields are left alone, they may have joined after the initial migration and are still owed their defaults.The flag is stored as a user option now, so it is scoped per site on multisite, which matches extra fields being per-site posts.
get_user_option()falls back to the unprefixed key, so flags written before this keep working and nobody gets re-provisioned. There is noadd_user_option(), so the seeder adds the site prefix by hand to keep the atomic claim.There is no cleanup routine for duplicates that already exist. Matching them by title would mean force-deleting user-editable content on
init, and they can be removed in Settings, ActivityPub. Existing duplicates stop multiplying either way.Other information:
Supersedes #3638 by @faisalahammad, which fixed the duplication with a per-user title lookup plus a cleanup migration.
Testing instructions:
wp option delete activitypub_db_versionand load any page. No second "Powered by" field should show up.activitypub_default_extra_fieldsflag, and that a user created after the upgrade still gets Blog/Profile/Homepage defaults on first fetch.Changelog entry
A changelog entry was added manually as
.github/changelog/fix-powered-by-flag.Changelog Entry Details
Significance
Type
Message
The "Powered by WordPress" profile field is now only added once, and stays gone when you delete it.