WordPress.org

Make WordPress Core

Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#11442 closed defect (bug) (fixed)

Untrashed comments could be deleted by wp_scheduled_delete()

Reported by: nacin Owned by:
Milestone: 2.9 Priority: high
Severity: normal Version: 2.9
Component: Trash Keywords: needs-patch
Focuses: Cc:

Description

If you trash a comment, then change its comment status (say to approved) without running wp_untrash_comment(), the _wp_trash_meta_time comment meta will still exist.

wp_scheduled_delete() will then delete the comment once the comment meta time is old enough.

This isn't as much of an edge case, nor does it require a direct DB edit or for a plugin to get involved. The comment.php AYS form (when clicking a link in wp_notify_moderator() email) doesn't check what the comment's current status is. Thus, if the comment was already trashed, and it is then approved, wp_untrash_comment() will not be run and the comment meta will still exist.

First solution, prevent the blocker:

Have wp_scheduled_delete() also check whether the comment is currently in trash.

Second solution, prevent the whole situation from occurring, which would be good for 3.0:

Implement #11441: Comment moderation AYS should provide feedback on comment's current status. I hinted to this blocker in that ticket without realizing it was a blocker:

(For example, a trashed comment would need to first be untrashed before being approved. This doesn't happen now, which means meta is not cleaned up, etc.)

Working on a quick patch for wp_scheduled_delete() now.

Attachments (5)

11442.diff (1.4 KB) - added by nacin 5 years ago.
11442.2.diff (1.4 KB) - added by nacin 5 years ago.
Garbage collector added to wp_scheduled_delete()
11442.3.diff (738 bytes) - added by nacin 5 years ago.
11442.4.diff (1.2 KB) - added by caesarsgrunt 5 years ago.
11442.5.diff (8.0 KB) - added by caesarsgrunt 5 years ago.

Download all attachments as: .zip

Change History (29)

comment:1 nacin5 years ago

  • Keywords has-patch added

This patch prevents wp_scheduled_delete() from deleting a comment with trash meta that isn't currently in the trash. Provides coverage for posts as well.

There should also be some scheduled cleanup to remove trash meta keys for items not in the trash.

nacin5 years ago

comment:2 azaozz5 years ago

The double-check sounds good but instead of selecting only posts/comments that are currently in the trash, perhaps better to select all that are scheduled (as at the moment) and then check if the status == 'trash'. Then you can remove the trash timestamp meta for items that are not trashed.

nacin5 years ago

Garbage collector added to wp_scheduled_delete()

comment:3 follow-up: nacin5 years ago

Took a slightly different route, patch attached.

comment:4 in reply to: ↑ 3 azaozz5 years ago

Replying to nacin:

Took a slightly different route, patch attached.

Doing this directly with SQL would bypass the API and all hooks (although it may be acceptable in this case). Going through the API may be slower but would let plugins run too.

comment:5 caesarsgrunt5 years ago

Doing this stops plugins from being able to use wp_scheduled_delete() for other status such as spam (could be a common use case).

Better would be to make wp_set_comment_status() check whether the comment is spam or trash before setting the status, and if so run wp_untrash_comment() or wp_unspam_comment() first.

comment:6 caesarsgrunt5 years ago

  • Keywords has-patch removed

We could add an argument to wp_untrash_comment() and wp_unspam_comment() which allows one to override the previous status read from the db and set an arbitrary new one. Then wp_set_comment_status() can check the status of the comment, and if it is trash or spam call wp_untrash_comment() or wp_unspam_comment() with this parameter specifying the new status.

Sorry if that's not a good explanation... I'll upload a patch later.

comment:7 nacin5 years ago

I'm thinking we tie this into wp_transition_comment_status(). We could possibly even add a default action to handle it:

Either in wp_transition_comment_status() or tied to the transition_comment_status hook:

		if ( 'trash' == $old_status )
			wp_untrash_comment( $comment );
		if ( 'spam' == $old_status )
			wp_unspam_comment( $comment );

comment:8 nacin5 years ago

Never mind, that doesn't make sense. Too late in the process.

In wp_set_comment_status(), before the $wpdb->update:

	if ( 'trash' == $comment_old->comment_approved && $status != 'trash' )
		wp_untrash_comment( $comment_id );
	elseif ( 'spam' == $comment_old->comment_approved && $status != 'spam' )
		wp_unspam_comment( $comment_id );

I think that takes care of this. I can't think of a case why the extra parameter is necessary, because otherwise the situation this patch would prevent can occur.

comment:9 caesarsgrunt5 years ago

No, not really necessary; just an alternative way of going about it. But probably what you've just described, which is what I said in my first comment, is best. Just ignore my second comment...

nacin5 years ago

comment:10 nacin5 years ago

  • Keywords has-patch added

comment:11 caesarsgrunt5 years ago

  • Keywords commit added

comment:12 nacin5 years ago

  • Keywords has-patch commit removed

Gah, that puts it into a redirect loop when wp_un(spam|trash)_comment is called.

comment:13 caesarsgrunt5 years ago

:-o

Oh dear. Time to start thinking again...

caesarsgrunt5 years ago

comment:14 caesarsgrunt5 years ago

  • Keywords has-patch added

I think 11442.4.diff fixes the problem satisfactorily.

This could, of course, be taken one step further by merging wp_trash_comment, wp_untrash_comment, wp_spam_comment, and wp_unspam_comment into wp_set_comment_status altogether.

caesarsgrunt5 years ago

comment:15 caesarsgrunt5 years ago

11442.5.diff takes the extra step mentioned in my previous comment, by merging wp_trash_comment, wp_untrash_comment, wp_spam_comment, and wp_unspam_comment into wp_set_comment_status.

comment:16 follow-up: nacin5 years ago

Patch 4: I like it, and it looked like what I was considering but I haven't had time to re-patch.

I'm trying to run it through my head for how trashed -> spammed (and vice versa) would work, but this appears to fix the blocker.

Patch 5: I actually liked the simple wp_(action)_comment() functions as an API. They've also been around long enough in beta that removing them might be a compat issue. Combining them I suppose makes sense though.

Do we add back all sorts of pre- and post- actions?

Spam didn't previously have an expiration time; they just got wiped by wp_scheduled_delete() (at least how I understood it).

comment:17 in reply to: ↑ 16 scribu5 years ago

Replying to nacin:

Patch 5: I actually liked the simple wp_(action)_comment() functions as an API. They've also been around long enough in beta that removing them might be a compat issue. Combining them I suppose makes sense though.

Agree: the wp_(action)_comment() functions should stay, even though they're just wrappers for wp_set_comment_status().

Do we add back all sorts of pre- and post- actions?

Absolutely.

comment:18 follow-up: caesarsgrunt5 years ago

Replying to nacin:

I'm trying to run it through my head for how trashed -> spammed (and vice versa) would work

Shouldn't ever happen...

Patch 5: I actually liked the simple wp_(action)_comment() functions as an API. They've also been around long enough in beta that removing them might be a compat issue. Combining them I suppose makes sense though.

I don't think removing them could be a compat issue. Anyone developing a plugin against a beta release should be prepared to have to make changes. And these are pretty minor changes from an API point of view.

Do we add back all sorts of pre- and post- actions?

I don't understand. What do you mean?

Spam didn't previously have an expiration time

It still doesn't - the time it was spammed gets stored in the DB like trash, because that's just simpler, but it is never automatically deleted.

they just got wiped by wp_scheduled_delete() (at least how I understood it).

No, spam is never automatically deleted at any point.

comment:19 caesarsgrunt5 years ago

We could make all the changes in patch 5, but keep the wp_(action)_comment() functions just as wrappers - eg

function wp_trash_comment($id) {
    return wp_set_comment_status($id, 'trash');
}

but I don't think it's really necessary. After all, why should trash and spam have separate functions when no other status does?

comment:20 in reply to: ↑ 18 ; follow-up: nacin5 years ago

Replying to caesarsgrunt:

Replying to nacin:

I'm trying to run it through my head for how trashed -> spammed (and vice versa) would work

Shouldn't ever happen...

That's the point of the ticket. If a comment is already trashed, a link in a notif email will still take you to the comment SYS form and allow a change in status without untrashing. I'm going to work on a patch later today for that but I anticipated that being 3.0, as it isn't a regression (as long as the blocker is fixed).

Patch 5: I actually liked the simple wp_(action)_comment() functions as an API. They've also been around long enough in beta that removing them might be a compat issue. Combining them I suppose makes sense though.

I don't think removing them could be a compat issue. Anyone developing a plugin against a beta release should be prepared to have to make changes. And these are pretty minor changes from an API point of view.

But they're still simple, easy to use, and named well. I don't care so much either way.

Do we add back all sorts of pre- and post- actions?

I don't understand. What do you mean?

Ex.: The trash_comment hook ran before a comment was trashed, and a trashed_comment hook ran once trashed (if successful).

comment:21 in reply to: ↑ 20 caesarsgrunt5 years ago

Replying to nacin:

But they're still simple, easy to use, and named well.

So is wp_set_comment_status($id, 'trash'). But I don't care much either way either...

Ex.: The trash_comment hook ran before a comment was trashed, and a trashed_comment hook ran once trashed (if successful).

Oh. Well, this doesn't happen for any other statuses, but it would be easy enough to make it so that this happened for all statuses.

comment:22 azaozz5 years ago

  • Keywords needs-patch added; has-patch removed
  • Severity changed from blocker to normal

This is a double-check if the comments/posts have been properly "untrashed" and to prevent deleting them when not. All it needs to do is look at the "status" field and delete the meta timeout if it's not 'trash'.

Don't think we should be removing functions and filters that have been in core for few months, also the posts and the comments trashing API should be similar and easy to read/understand.

comment:23 automattor5 years ago

  • Resolution set to fixed
  • Status changed from new to closed

(In [12412]) Check post and comment status before emptying trash, fixes #11442

comment:24 azaozz5 years ago

If refactoring of the comment trash/untrash is needed, please open another ticket.

Note: See TracTickets for help on using tickets.