Skip to content

Use wp_term_taxonomy.parent to link feeds to subscriptions#594

Merged
akirk merged 10 commits intoremove-friendship-functionalityfrom
feeds-as-term-children
Mar 20, 2026
Merged

Use wp_term_taxonomy.parent to link feeds to subscriptions#594
akirk merged 10 commits intoremove-friendship-functionalityfrom
feeds-as-term-children

Conversation

@akirk
Copy link
Copy Markdown
Owner

@akirk akirk commented Mar 9, 2026

Summary

  • Stores feed terms as children of their subscription term via wp_term_taxonomy.parent instead of wp_term_relationships object links
  • Adds a migration (link_feeds_as_term_children) to convert existing installations; uses clean_term_cache() for targeted cache invalidation after direct SQL updates
  • Removes the legacy get_objects_in_term fallback from get_all_friend_users() and adds hide_empty => false to all User_Feed term queries (feed terms have no object links so their count is 0)

Test plan

  • All 316 tests pass (composer test)
  • Migration tests cover: convert_from_user(), convert_friend_users_batch(), and link_feeds_as_term_children()
  • Verify feeds are correctly linked after migration on an existing site with WP-user-backed subscriptions

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 9, 2026

Test this PR in WordPress Playground

You can test this pull request directly in WordPress Playground:

Launch WordPress Playground

This will install and activate the plugin with the changes from this PR.

@akirk akirk force-pushed the feeds-as-term-children branch 2 times, most recently from 984c12b to 10ab921 Compare March 10, 2026 07:14
akirk added 8 commits March 11, 2026 11:00
Instead of wp_set_object_terms() (which links feeds to subscriptions via
wp_term_relationships), store the subscription term_id in the parent field
of wp_term_taxonomy for each feed term.

This eliminates the off-label use of the object relationship table for
term-to-term links, which caused sync issues when WordPress's internal
machinery modified or recounted relationships for non-post objects.

Subscription now overrides get_feeds() and save_feeds() to use the parent
field. User_Feed::get_all_friend_users() prefers the parent lookup, falling
back to the legacy object relationship path for feed terms not yet migrated.

A batched migration (link_feeds_as_term_children) converts existing
feed-to-subscription object relationships to parent links and removes
the now-redundant wp_term_relationships rows.

Also removes the dead User_Feed::save_multiple() method.
…eries

- Remove get_objects_in_term fallback from get_all_friend_users(); feeds
  now exclusively use wp_term_taxonomy.parent to link to subscriptions
- Add hierarchical => true to feed taxonomy registration so parent queries work
- Add hide_empty => false to all User_Feed term queries (get_by_url,
  get_all_users, get_all_due, get_by_parser) since feed terms have count=0
  in the new parent-based approach
- Update test-feed.php to use User::create() instead of WP user factory,
  matching the Subscription-based architecture
- test_convert_friend_user_to_subscription: verifies Subscription::convert_from_user()
  migrates feeds (parent set via direct SQL), posts (author=0, subscription term),
  and user options from a WP-user-backed friend to a virtual subscription
- test_convert_friend_users_batch: verifies the batch migration finds users with
  old friend/acquaintance roles and converts them all to subscriptions
- test_link_feeds_as_term_children: verifies the batch that converts pre-existing
  object_terms feed relationships (subscription_term_id → feed_term) to the new
  parent-based hierarchy, and removes the old term_relationships entries

Note: wp_cache_flush() is required after these migrations in tests because the
direct SQL updates bypass WordPress's object cache; in production this is not an
issue since migrations run in a cron/batch context before the next page request.
Remote_Actors::get_by_uri() returns a WP_Post, not an Actor object.
Pass it through get_actor() to get the Actor with get_image()/get_summary().
In multisite, delete() calls remove_user_from_blog() rather than
wp_delete_user(), so the user still exists network-wide. Check that the
user is either deleted or no longer a member of the current blog.
The direct $wpdb->query UPDATE on term_taxonomy.parent doesn't invalidate
WordPress term caches, causing get_feeds() to return stale results.
…sion

The delete_user hook in Admin::delete_user() finds feeds via object_id-based
term relationships and deletes them. Since convert_from_user sets the parent
but leaves the old term_relationships intact, the subsequent user deletion
would delete the just-migrated feeds. Remove the old relationships after
re-parenting to prevent this.
wp_remove_object_terms() triggers WordPress hooks that cause side effects
breaking the migration. Use a direct $wpdb DELETE instead, followed by
clean_term_cache to invalidate stale caches. This also prevents the
Admin::delete_user hook from finding and deleting the just-migrated feeds
(which only happened for users with the subscription capability).
@akirk akirk force-pushed the feeds-as-term-children branch from d0c4d9e to ca76be1 Compare March 11, 2026 10:01
akirk added 2 commits March 18, 2026 05:54
get_private_url() still called $friends->access_control->append_auth()
which was removed with the friendship functionality. This crashed the
cron on every RSS feed poll, breaking automatic feed checking since the
migration deployed on March 11.
Private URL authentication was part of the removed friendship
functionality. Replace all get_private_url() calls with get_url().

Add a test that verifies cron_friends_refresh_feeds() can resolve
the friend user via parent term and create posts — the flow that
was broken by the stale access_control reference.
@akirk akirk merged commit ae2b64a into remove-friendship-functionality Mar 20, 2026
25 checks passed
@akirk akirk deleted the feeds-as-term-children branch March 20, 2026 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant