0

For a plugin, I need to build my own very early post content and comment content filter. Post content/text changing works, i.e. the modifications end up in the client's browser. But my comment content/text modifications somehow are not persistent, i.e. the client receives the original comment text.

The point in time I "hook in" is defined by the template_redirect hook. I then execute something like this:

global $wp_query;

// Iterate over all posts in this query.
foreach ($wp_query->posts as $post) {
    // Edit post text
    $post->post_content = "foo"; // works: ends up at the client

    // Iterate over all approved comments belonging to this post
    $comments = get_approved_comments($post->ID);
    foreach ($comments as $comment) {
        // Edit comment text
        $comment->comment_content = "bar"; // this one is lost
        } 
    }

As indicated via the source comments above, $post->post_content = "foo"; has effect in this context, but $comment->comment_content = "bar"; doesn't.

To track this down at least a bit more, I applied a debug filter to the post content and to the comment content:

add_filter('the_content', 'var_dump');
add_filter('comment_text', 'var_dump');

After the content modification routine above, these filters print "foo" in case of post content, but the comment content is printed unchanged (the original content is printed).

Hence, $comment->comment_content = "bar"; seems to be a local modification, while $post->post_content = "foo"; works as desired: globally.

Or is the database even queried two times for comments so that my modification somehow gets overwritten at some point?

I've tried to work with $wp_query->comments, too. But this variable is NULL at the point in time I want and need to hook in.

The final and primary question is:

In my loop above, what do I have to do, to modify the comment content persistently?

FYI: I am using WordPress 3.0.1

5
  • Can you explain why you need the filter to run this early? It may help someone find a better answer for you as the normal filters would be to use the 'comment_text' and 'the_content' to filter these unless you need it to be earlier for some reason. Commented Nov 25, 2010 at 20:44
  • Of course I can:-) -> I definitely need to run before the wp_head trigger. This is because I need to include CSS code to the HTML header that is dynamically created based on the post/comment content. Commented Nov 25, 2010 at 21:50
  • Could you add that code to question? It would make much more sense to query/filter at that stage rather than mess with global variables.
    – Rarst
    Commented Nov 26, 2010 at 6:52
  • Thanks for your comment, Rarst. I don't want to blow the question up much more. It's like this: I filter a text for <pre arguments> code </pre> occurrences and put this into GeSHi, which creates a) highlighted HTML for code and b) the corresponding CSS code. The HTML from (a) ends up "in the text", the CSS code from (b) has to end up in the html head. Commented Nov 29, 2010 at 15:43
  • Furthermore, it is/was my objective to replace the <pre args>code</pre> occurrence as early as possible with a unique identifier, and to replace this identifier as late as possible by the highlighting HTML. Commented Nov 29, 2010 at 15:50

2 Answers 2

2

The function that includes the comments template also (re)loads the comments. This means that whatever you do before that point, if you don't save it to the database it will not be used.

There is no way to prevent this SQL query from happening, but you can override the results by hooking into the comments_array filter. I would save your modifications in an array keyed by the comment ID, so you can do quick lookups and replace contents if needed.

$wpse4522_comments = array();

// Somewhere in your template_redirect (why not wp_head?) hook:
foreach ($wp_query->posts as $post) {
    // Edit post text
    $post->post_content = "foo"; // works: ends up at the client

    // Iterate over all approved comments belonging to this post
    $comments = get_approved_comments($post->ID);
    foreach ($comments as $comment) {
        // Edit comment text
        $GLOBALS['wpse4522_comments'][$comment->comment_ID] = 'bar';
    } 
}

// And this loads the content back into the array from comments_template()
add_filter( 'comments_array', 'wpse4522_set_comments_content' );
function wpse5422_set_comments_content( $comments, $post_id )
{
    global $wpse4522_comments;
    foreach ( $comments as &$comment_data ) {
        if ( array_key_exists( $comment_data->comment_ID, $wpse4522_comments ) ) {
            $comment_data->comment_content = $wpse4522_comments[$comment_data->comment_ID];
        }
    }
    return $comments;
}
1
  • Thanks for making clear that this is not possible with less then two comment queries! Commented Nov 29, 2010 at 16:03
1

Without knowing much more about what you're tyring to accomplish, there are a few possible solutions.

One is to continue doing what you're currently doing to, but to also add a filter to 'comment_text' to alter the comment output. The downside with this is that you're querying the comments multiple times.

Another option is to start an output buffer on 'template_redirect' and print a placeholder on the 'wp_head' hook to mark a spot in the header. Then use the 'comment_text' and 'the_content' filters to alter the output and check for whatever markers you're looking for. Then, in the output buffer callback, have it replace that marker you put in the header with whatever css you need to add. The only issue with this solution is that the buffer size set on the server may not be enough depending on how much content you have in a single page or how small the buffer is.

1
  • Thank you for your answer, especially for the output buffer hint. I will definitely look into this, just out of interest. Commented Nov 29, 2010 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.