Skip to content

Fix a fatal error when the ActivityPub plugin is not active - #714

Merged
akirk merged 2 commits into
mainfrom
fix/activitypub-class-without-plugin
Sep 4, 2026
Merged

Fix a fatal error when the ActivityPub plugin is not active#714
akirk merged 2 commits into
mainfrom
fix/activitypub-class-without-plugin

Conversation

@akirk

@akirk akirk commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Without the ActivityPub plugin, /friends/ dies mid-render: the page stops inside the first post's header and nothing after it is sent. Profile pages go the same way.

Feed_Parser_ActivityPub is required only from the friends_load_parsers callback in friends.php, which returns early when \Activitypub\Activitypub doesn't exist — and there is no autoloader. But the templates that render an author's display name call its custom emoji helpers regardless, for every post:

  • templates/frontend/parts/header.php, parts/header-status.php — every post in the feed
  • templates/frontend/author-header.php — every profile page
  • includes/class-frontend.php, includes/class-blocks.php — the author-name blocks

Friends works standalone, so this hits anyone who hasn't installed the ActivityPub plugin, or who deactivates it.

Changes

Rather than scattering class_exists() over five call sites, the display name goes through a filter, which is the gating this plugin already uses for exactly this — two lines below the emoji call, header.php does do_action( 'friends_post_author_meta', $friend_user ), and the ActivityPub parser is what hooks it.

  • New friends_author_display_name_html filter, applied wherever an author's display name is rendered, defaulting to esc_html( $display_name ).
  • Feed_Parser_ActivityPub::author_display_name_html() hooks it from the constructor, alongside friends_post_author_meta. The parser is only constructed while the ActivityPub plugin is active, so the emoji rendering is added exactly then and the escaped default stands otherwise.

Two other places reached the parser unguarded, and get the gating the rest of their own file already uses:

  • templates/frontend/author-header.phpget_actor_acct_from_attributed_to(). A feed can still be marked activitypub in the database with the plugin gone. Returns '' in that case, which is what the helper itself does anyway.
  • includes/class-user.phpdetermine_mastodon_api_user() in mastodon_api_account_id(), which is hooked from the Enable Mastodon Apps integration, so it runs whenever EMA is active, with or without ActivityPub. Its two sibling call sites at :1178 and :1290 were already guarded; this one was missed.
  • includes/class-user.phpmastodon_entity_relationship() reads Feed_Parser_ActivityPub::SLUG after its own class_exists() if/else, on a path reached when the class is absent. It compares against the 'activitypub' literal now, the way author-header.php already does.

Everything else that touches the parser is already behind a class_exists/function_exists check: the follower counts in the stats block and widget, direct message delivery status, webfinger resolution, get_activitypub_actor_id(), and the ::SLUG uses across the migrations.

Two references remain formally unguarded and are deliberately left alone, since neither is reachable without the plugin:

  • templates/frontend/parts/activitypub/follow-link.php:9 is only ever rendered from Feed_Parser_ActivityPub::friends_post_author_meta().
  • includes/class-migration.php:2815 sits downstream of process_potential_reply_post(), which calls \Activitypub\Http::get_remote_object() on its first line.

Testing instructions

Two Playground instances on the same fixture (a subscription with three status posts), one without the ActivityPub plugin and one with it installed and active. A probe mu-plugin reports what is loaded and hooked on a /friends/ request:

ActivityPub plugin parser class loaded friends_author_display_name_html hooked
without no no no — filter returns the escaped default
with yes yes yes

Pages, before and after, without the ActivityPub plugin:

page before after
/friends/ 15,294 bytes, 1 truncated article 49,542 bytes, 3 articles
/friends/newssite/ 13,386 bytes, 0 articles 49,509 bytes, renders

After the change /friends/, /friends/newssite/, /friends/messages/, /friends/followers/ and the Friends and Settings admin pages all return 200 and close their HTML in both configurations, with no JS errors, and the feed shows 3 articles, 2 link preview cards and the correct author names either way.

php -l and phpcs --standard=phpcs.xml clean on all 7 touched files. PHPUnit was not run locally (no WordPress test library on this machine) — leaving that to CI. No test touches the changed code paths directly; the emoji helpers themselves are unchanged and their existing tests still call them as before.

Changelog entry

  • Automatically create a changelog entry from the details below.
Changelog Entry Details

Type

  • Fixed - for any bug fixes

Message

Fix a fatal error that stopped the friends page from rendering when the ActivityPub plugin is not active.

https://claude.ai/code/session_01J7aozaEFaZ3vLaLXith1qm

@akirk
akirk force-pushed the fix/activitypub-class-without-plugin branch from 9be1c0c to 2583389 Compare September 4, 2026 11:50
@akirk akirk changed the title Fix a fatal error when the ActivityPub plugin is not active Move ActivityPub data helpers out of the parser Sep 4, 2026
Feed_Parser_ActivityPub is only required from the friends_load_parsers
callback, which returns early when the ActivityPub plugin is missing.
The templates rendering an author's display name called its custom emoji
helpers regardless, so without that plugin /friends/ died mid-render,
inside the first post's header, and the profile pages with it.

Render the name through a new friends_author_display_name_html filter
instead, defaulting to the escaped display name. The parser hooks it
from its constructor, next to friends_post_author_meta, so the emoji are
added exactly while the parser is registered and the default stands
otherwise. No class_exists at the call sites.

Two more places reached the parser unguarded and get the gating the rest
of their file already uses: the actor handle on the profile header, and
determine_mastodon_api_user() in User::mastodon_api_account_id(), which
runs whenever Enable Mastodon Apps is active - with or without
ActivityPub. Its two sibling call sites were already guarded.

The relationship check below it used Feed_Parser_ActivityPub::SLUG on a
path that is reached without the plugin; it compares against the literal
now, the way the templates already do.

Claude-Session: https://claude.ai/code/session_01J7aozaEFaZ3vLaLXith1qm
@akirk
akirk force-pushed the fix/activitypub-class-without-plugin branch from 1282f17 to 8628b89 Compare September 4, 2026 12:05
@akirk akirk changed the title Move ActivityPub data helpers out of the parser Fix a fatal error when the ActivityPub plugin is not active Sep 4, 2026
@akirk
akirk merged commit f97ffd0 into main Sep 4, 2026
27 checks passed
@akirk
akirk deleted the fix/activitypub-class-without-plugin branch September 4, 2026 12:11
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