Nobody reported this bug. I found it because on 2 July I ran the claim flow end to end through Playwright MCP, including clicking the verification link inside a real Gmail inbox. The flow belongs to a membership site: a user submits a claim on a profile, gets a verification token, clicks the link in the email, staff get notified, then staff open the claim post in wp-admin and approve it through a "Claim review" metabox. After approval, the profile linking function runs and the profile officially has an owner.
Every step before the staff step went smoothly. The moment I opened the claim post in wp-admin, the "Claim review" box was not there. Not empty, not erroring, simply never rendered. Which meant staff could not approve a single claim at all, because the approve button lived inside that box. That QA session surfaced three new bugs, and this one was the most embarrassing, because the root cause was a single argument out of place.
Why this happens
The theme deliberately uses hand-rolled metaboxes rather than ACF, as a convention. So the registration is a plain add_meta_box() inside the claim flow file. According to the documentation, the parameter order is $id, $title, $callback, $screen, $context, $priority. The broken call skipped $screen and went straight to context and priority, roughly like this:
add_meta_box(
'mship_claim_review',
'Claim review',
'mship_render_claim_review',
'side',
'high'
);What I meant by 'side' was the context, the box was supposed to sit in the sidebar. What WordPress read was $screen = 'side' and $context = 'high'. The metabox was registered for a screen literally named "side". No such screen exists anywhere in wp-admin, so the box was never asked to render.
What kept the bug alive is that add_meta_box() validates nothing. An unknown screen name is accepted as is, and a context of 'high', which is not a valid value, is accepted too. No notice, no warning. The PHP is valid, php -l is happy, and the claim edit page loads normally, just without its most important box. As long as nobody tries to approve a claim all the way through, this can sit there for months.
The fix
Pass null for $screen, then move context and priority into their proper positions:
add_meta_box(
'mship_claim_review',
'Claim review',
'mship_render_claim_review',
null,
'side',
'high'
);With null, WordPress uses whatever screen is current at the time of the call. If you want to be explicit, the post type name can go directly into the $screen slot. The point is the same: the fourth position has to hold something that means a screen, not be skipped.
While the box was open again, I added a visible conflict warning line inside it. If the claim targets a profile that already has an owner, the box shows the owner recorded in the _mship_claim_conflict meta together with a "NOT transferred" note, so staff know their approval will not move ownership. The account name shown in the "Matching account" line and in that warning comes from a display name helper, never the random login slug, because I had already complained about seeing that slug in emails.
The fix was deployed straight over SSH and committed together with two other bugs from the same QA session: a form time-trap that broke on pages cached by Cloudflare because its timestamp was baked into the HTML past the 1800 second window, and a "View profile" link on the account page that pointed at the editorial route instead of the commercial profile route. Three bugs, three different causes, one commit.
What I verified afterwards
Once the box rendered, I repeated the approval from wp-admin and checked the ownership map. The claim post stores the linked user ID, the profile stores the owner ID, a claimed flag and a matching post_author, and the user stores the profile ID. Everything points at everything else.
The conflict scenario was tested as well: a second user's claim on an already owned profile, when approved, writes _mship_claim_conflict with the existing owner, does not transfer ownership, and the staff warning renders in the box. The ownership write itself runs from the save_post_mship_claim hook and is gated on current_user_can('edit_post'), so there is always a human in wp-admin pressing approve, never an automatic path.
One honest note: a day later, on 3 July, a different bug showed up in the same metabox. The first approval through that metabox never persisted, the status stayed at verified, and the metabox gave no feedback at all. That is a separate bug from the 'side' argument issue, but the pattern is the same: a box failing silently.
Lessons
add_meta_box() has six positional parameters and none of them are validated. Skipping $screen produces no error, only a metabox registered to a fictional screen that never shows. When an admin box vanishes without a trace, count the arguments before you suspect hooks or capabilities.
The bigger point: this bug only surfaced because the flow was driven all the way to the human step instead of stopping at "email sent". The staff approval step is the one least likely to be clicked during development, and that is exactly where the box was missing.