Skip to content

Tell logged-out users to log in again instead of posting an empty comment - #267

Merged
lancewillett merged 2 commits into
masterfrom
fix/nopriv-write-missing-message-fields
Oct 16, 2026
Merged

lancewillett merged 2 commits into
masterfrom
fix/nopriv-write-missing-message-fields

Conversation

@bor0

@bor0 bor0 commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Proposed Changes

  • In o2_NoPriv_Write_API::create_comment(), fail with a logged_out error ("You have been logged out. Please log in again to comment.") when the message's author carries a userLogin.
  • Move the message-to-$_POST remap into get_comment_fields() and default missing fields.
  • Reject non-object messages, and messages without a type, in init().
  • Add PHPUnit coverage in tests/phpunit/test-nopriv-write-api.php.

When a user's session expires, or they log out in another tab, the page still thinks they're logged in. The comment view then sends author as the current user (userLogin, userNicename, …, see js/views/comment.js:237) instead of the name/email/url form fields, and the request lands on the nopriv handler. create_comment() read author->name, email and url, logged a warning for each, and passed an empty author to wp-comments-post.php, which rejects the comment with a generic "please fill the required fields" error. The comment view already shows errorText, so the user now sees why the comment failed.

Seen in production on make.wordpress.org:

E_WARNING: Undefined property: stdClass::$name in inc/nopriv-write-api.php:92
E_WARNING: Undefined property: stdClass::$email in inc/nopriv-write-api.php:93
E_WARNING: Undefined property: stdClass::$url in inc/nopriv-write-api.php:94

Hand-crafted requests such as {"type":"comment","postID":999999999,"contentRaw":"test"} also logged Undefined property: stdClass::$parentID (line 91) and more. These now get empty defaults and are rejected by core as before.

A genuinely logged-out commenter is unaffected: that form sends author as { name, email, url } with no userLogin.

Testing Instructions

  • Log in, open a post, then log out in another tab. Wait for the first tab to show "Your session has expired" (the next poll refreshes the nonce), then submit a comment there. Submitting before that prompt fails the nonce check with "Invalid or expired nonce" on both branches. On master, the warnings above are logged and the comment fails with "please fill the required fields". On this branch, the "You have been logged out" error is shown.
  • Logged out, comment with name and email as usual. The comment still posts.
  • vendor/bin/phpunit --filter NoPrivWriteAPITest passes. The tests fail with Undefined property: stdClass::$name without the fix.

🤖 Generated with Claude Code

…ment

When a user's session expires (or they log out in another tab), the page
still thinks they are logged in, so o2 sends `author` as the current user
(`userLogin`, `userNicename`) to the nopriv write handler. create_comment()
then read `author->name`, `email` and `url`, which aren't there, logged
three undefined property warnings, and handed wp-comments-post.php an empty
author, which rejects the comment with "please fill the required fields".

Detect that case and fail with a "log in again" message the comment view
shows. Default the remaining fields so hand-crafted messages (no
`parentID`, no `author`, a non-object payload) are rejected by core or the
type check instead of logging warnings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@bor0
bor0 requested a review from lancewillett October 15, 2026 11:44
@lancewillett

Copy link
Copy Markdown
Contributor

tests/phpunit/test-nopriv-write-api.php:37: set $_SERVER['REQUEST_METHOD'] = 'POST' in this test and restore it afterward. The plugin test bootstrap leaves it as GET, so if the userLogin guard ever regresses, create_comment() reaches wp-comments-post.php, which calls a bare exit on non-POST requests. PHPUnit then stops with status 0, skips every later test, and CI shows green.

AI review · claude-opus-5-5

@lancewillett lancewillett left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 blocker, left a comment.

If the userLogin guard regressed, create_comment() would reach
wp-comments-post.php, which exits on anything but POST. The test only
failed loudly because the bootstrap's earlier output turns that branch's
header() call into a warning. Make the request a POST so a regression
always surfaces as a test failure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@bor0
bor0 requested a review from lancewillett October 16, 2026 08:40

@lancewillett lancewillett left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran it locally: with the userLogin guard removed, the test now errors loudly, and you were right that the header warning already caught it before.

AI review · claude-opus-5-5

@lancewillett
lancewillett merged commit 129e5f6 into master Oct 16, 2026
3 checks passed
lancewillett added a commit that referenced this pull request Oct 16, 2026
A Docker MySQL recipe for bin/install-wp-tests.sh, verified from cold
containers, and the testing patterns from #267: run tests that can reach
wp-comments-post.php as POST, capture die_failure() output through
wp_die_ajax_handler, and prove guard tests fail when the guard is removed.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants