Make WordPress Core

Opened 7 weeks ago

Last modified 7 weeks ago

#62644 reopened defect (bug)

Editing comments as an admin, in the Admin UI, filters the HTML elements of the comment as though the edit was done by the original author.

Reported by: turbodb's profile turbodb Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.7.1
Component: Comments Keywords:
Focuses: Cc:

Description

Problem Description:

I know that comments don’t allow img elements by default (for unregistered users). For privacy/spam reasons, of course. On my site, I manually moderate all comments, so this is less of an issue for me, and there are times when it is important for people (not signed-in users) to be able to link to images.

Repro Steps:

  1. Add the following code to functions.php, which will allow non-registered users to include the <img> element in comment contents.
function add_post_comment_html_tags( $commentdata ) {

  global $allowedtags;
  $new_tags = [
    'img'=> [
		'src'=> true,
		'class'=> true,
		'style'=> true,
		'alt'=> true
    ]
  ];
  $allowedtags = array_merge( $allowedtags, $new_tags );
}
add_action('pre_comment_on_post', 'add_post_comment_html_tags' );

  1. As a non-registered user, leave a comment on a post, utilizing the <img> HTML element to include an image.

===> Note that the image is successfully allowed into the comment.

  1. Log in to the site as an administrator and navigate to the Comments page in Admin UI.
  1. Edit (or Quick Edit) the comment, and change the contents slightly, but leave the <img> element alone.
  1. Save your changes.

Result:

Once the comment is saved by the admin, the <img> element is removed entirely, even though the administrator can create comments - either in the admin UI or frontend - that contain <img> elements.

This happens because the comment edit is committed as / impersonates the original comment author on save, and is not executed as the current editor (administrator) in the Admin UI. Further, because the comment already exists, the pre_comment_on_post action is not called, so <img> is not added to the global $allowedtags.

Expect:

I would expect one of two things:

  1. That edits to comments in the admin UI are performed *as the current user editing the comment* instead of as the original comment author.
  1. That there be a way to modify the global $allowedtags for comment edits, in the same way that there is for comment creation.

Notes:

  1. I originally brought this up here, for a bit more context: https://wordpress.org/support/topic/how-to-prevent-editing-of-comments-as-admin-from-stripping-images/
  2. There may already be a filter/hook that serves this purpose, but I couldn't find one in the docs. I tried comment_save_pre, which did not work successfully.
  3. If the administrator edits a comment that was originally created by an administrator (or any user with the unfiltered_html capability), then the <img> is not removed. (as expected)

Change History (10)

#1 @yogeshbhutkar
7 weeks ago

Hi @turbodb,

Thank you for raising the ticket. I reviewed the issue described, and using the init hook instead of pre_comment_on_post resolved the problem for me.

That said, I wouldn’t consider the current approach the safest solution. A more robust approach would involve ensuring proper sanitization and escaping throughout the code. Additionally, creating a dedicated plugin, if one doesn’t already exist, would be a better practice, as changes made to the functions.php file risk being overwritten during updates.

Final code:

function add_post_comment_html_tags() {
	global $allowedtags;
	$new_tags    = array(
		'img' => array(
			'src'   => true,
			'class' => true,
			'style' => true,
			'alt'   => true,
		),
	);
	$allowedtags = array_merge( $allowedtags, $new_tags );
}
add_action( 'init', 'add_post_comment_html_tags' );

#2 @turbodb
7 weeks ago

Hi @yogeshbhutkar,

Thanks for the quick response, and the workaround suggestions. A couple thoughts on your suggestions:

  1. I agree with your suggestion of using a plugin rather than functions.php, and in fact, that is what I'm doing. I was trying to provide the simplest repro steps in the bug report, and functions.php seemed a lighter weight repro than creating a plugin.
  1. I know that I can use init, but that's a much heavier weight (riskier / larger surface area) solution than the one I'm looking for (to your point about looking for a "safer" solution). There are two reasons it is heavy-handed:
    • it runs every single page load, rather than only when comments are in play.
    • it adds/allows <img> in all cases, opening up a larger surface area than allowing it only for the case (comments) for which I want it to be allowed.

And, a clarification:

You stated:

...using the init hook instead of pre_comment_on_post resolved the problem for me.

To be clear - the pre_comment_on_post works perfectly when the comment is initially created, which is the only time I would expect it to run, since it is "pre" the comment being added on a post.

The time when it doesn't run - and I was suggesting that another hook should exist for this case - is when a comment is being edited in the Admin UI. I'd expect a hook such as pre_comment_edit or something of that nature.

Net net:
It seems to me that if there is a hook for "before comment creation," there should be a matching hook for "before comment edit," since, otherwise, there's no way to ensure that operations done during (and scoped to) creation are maintained during (and still scoped to) comment edits.

#3 @siliconforks
7 weeks ago

Did you try using the wp_kses_allowed_html filter, as suggested in the forum topic?

Example:

<?php

function my_wp_kses_allowed_html_for_comments( $html, $context ) {
        if ( 'pre_comment_content' === $context ) {
                $html['img'] = [
                        'src'=> true,
                        'class'=> true,
                        'style'=> true,
                        'alt'=> true
                ];
        }
        return $html;
}

add_filter( 'wp_kses_allowed_html', 'my_wp_kses_allowed_html_for_comments', 10, 2 );

#4 follow-up: @turbodb
7 weeks ago

Thanks for the suggestion @siliconforks.

Using the wp_kses_allowed_html filter might work, but in your example you've limited it to the 'pre_comment_content', which as I mentioned in the original bug, already works correctly using the hook of the same name.

Without that context limitation, using wp_kses_allowed_html has the same issue I've raised as using the init hook - namely that it's a much larger scope and opens up a much larger area than the targetted use of <img> that I'm aiming to allow here, which is only in comments.

By using wp_kses_allowed_html - unless there's a $context for editing comments, in which case, I should be able to use the specific hook for that $context - I would be allowing <img> everywhere that HTML is filtered,

#5 in reply to: ↑ 4 ; follow-up: @siliconforks
7 weeks ago

Replying to turbodb:

Using the wp_kses_allowed_html filter might work, but in your example you've limited it to the 'pre_comment_content', which as I mentioned in the original bug, already works correctly using the hook of the same name.

I'm not sure what you mean here? The pre_comment_content hook is not the same thing as the pre_comment_on_post hook. I believe that pre_comment_content is used for both posting new comments and editing existing comments.

#6 in reply to: ↑ 5 @turbodb
7 weeks ago

Replying to siliconforks:

Replying to turbodb:

Using the wp_kses_allowed_html filter might work, but in your example you've limited it to the 'pre_comment_content', which as I mentioned in the original bug, already works correctly using the hook of the same name.

I'm not sure what you mean here? The pre_comment_content hook is not the same thing as the pre_comment_on_post hook. I believe that pre_comment_content is used for both posting new comments and editing existing comments.

Ahh, yep, I was reading too quickly. Let me give that a shot and I'll report back. Is there somewhere I can find the list of valid $context values? There's not much indication of what those are on https://developer.wordpress.org/reference/functions/wp_kses_allowed_html/

#7 @turbodb
7 weeks ago

This did work, @siliconforks.

Should I be using this methodology for comment creation as well? If so, a pointer to the $context to use would be helpful.

Thanks.

#8 @siliconforks
7 weeks ago

The $context value could be basically anything (including custom values used by plugins, etc.). For comments I think you only need to worry about the pre_comment_content context as I believe this is used for both posting comments on the front-end of the site and editing comments in the admin section.

This is triggered by the pre_comment_content filter here, which will call the function wp_filter_kses, which sets the context to the value of current_filter() here - hence the context is named the same as the filter, pre_comment_content.

#9 @turbodb
7 weeks ago

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

Perfect, thanks.

This still seems like a strange misalignment between comment creation and editing (pre_comment_on_post vs. nothing for pre comment edit), but there clearly is a workaround that is scoped to comment content, so from that perspective, I could understand this being resolved as Won't Fix.

#10 @turbodb
7 weeks ago

  • Resolution invalid deleted
  • Status changed from closed to reopened

accidentally resolved, when checking the resolution values (didn't notice the radio button was autoselected.

Last edited 7 weeks ago by turbodb (previous) (diff)
Note: See TracTickets for help on using tickets.