AI Commenting Chaos Incarnate

As I tell my kids . . .1

Me: Remember Jim Groom?

Kid 1: The guy who shaved his head in our downstairs bathroom?

Kid 2: Bava bloody, bava?

Kid 3: From that creepy baby picture?

Kid 4: The guy you made a pumpkin carving of?

Kid 5: That guy on Santa’s lap?

Kid 6: That guy you made a gif of when he was eating chicken at Roy Rogers that you can’t find now?

Me: Yeah, that guy.

Well, now he’s doing a season of Madden 2001 and he wants to use AI to create the media coverage. Game summaries, fan sites, podcasts, etc.

Kid 12: What does he do for a job? Is this real?

Me: No. He’s an independently wealthy Italian tech magnate and he can spend his time doing strange things from a castle in Trento where he lives surrounded by old VCR tapes and 1980s arcade consoles. This is entirely not real and done purely for amusement.

To business

Since I did my proof of concept to extract text from images in WordPress using the OpeanAI API, I had the foundation to make a few of the things Jim and I had talked about a few months back happen. It’s just a matter of changing what fires off the API call and what data it contains.

I’ll walk through a couple pieces below but this plugin allows you to set how many comments you want to be generated on each post and then choose authors to reply to comments via a dropdown on the front end. All comment content is generated via the OpenAI API and integrates variables from the user profile.

This is all a matter of getting data and setting up triggers to make the data gets to the right place at the right time. I like the Rube Goldberg nature of programming.

Pull out the hardcoded API key

Previously, I had just written the API key directly in the PHP. To make life simpler, I opted to put the API key in an ACF options field. That way I could put the plugin in GitHub. I really should do something fancier but I think this is fine for our purposes.2

Getting the key is pretty straight forward.

    $apiKey = get_field('open_ai_key', 'option');

Generate comment

I should have captured each stage of this but . . . I didn’t.

Initially, I started by generating one comment when a post was published using the status change hook. So that enables us to fire a function when the publish transition happens.

wp_insert_comment is going to create the comment for us. When I do these things, I hard code a bunch of the variables and then work my way up. So on round one, I think I hardcoded everything except the post_id to make sure it was firing on post transition. It’s a bit aggressive because when I was testing it I got lazy and started firing it via a shortcode in addition to the transition. I did not realize that the shortcode would return an empty array for the post_id, which led to some weird errors . . . and so I spent a good deal of time troubleshooting a thing that would have worked fine if I hadn’t been so lazy. How many times do I need to learn the lesson of checking variables one by one? At least one more it seems.

  wp_insert_comment([
                'comment_post_ID'      => (int) $post_id,
                'comment_content'      => $generated_comment, //OpenAI gives us this
                'user_id'              => (int) $commenter->ID,
                'comment_author'       => sanitize_text_field($commenter->user_nicename),
                'comment_author_email' => sanitize_email($commenter->user_email),
            ]);

Persona details

To create more divergent comments, I opted to store the personality details with the users using ACF. That seemed nice and tidy. I made three fields: personality, writing style, and example post. I can fetch them and tie them into the OpenAI call. If I wanted to get extra lazy/fancy, I could use OpenAI to generate the users and these parameters. I might yet do that for the purse fractal insanity of it all.

 $personality = get_field('personality', 'user_' . $user_id);
 $style = get_field('writing_style', 'user_' . $user_id);
 $sample = get_field('sample_post', 'user_' . $user_id);

Random commenter

So now that I could create a comment, I wanted to randomize who made the comment. Since I can’t sort by RAND, I went the shuffle route. Initially, it was simpler and just returned one author but it was expanded because I wanted to be able to write multiple comments at once.

function ai_maddeness_get_random_author($number = 1, $override_user_ids = null) {
    if (!empty($override_user_ids)) {
        $user_ids = is_array($override_user_ids) ? $override_user_ids : [$override_user_ids];
        return get_users(['include' => $user_ids]);
    }

    $all_users = get_users(['role' => 'subscriber']);
    shuffle($all_users);
    return array_slice($all_users, 0, $number);
}

Reply to option

Now I wanted to add a dropdown of users for generating reply-to comments. I just asked this to be generated by Claude because it seemed boring to write. Very lazy on my part. Was my prompt better for having done similar things manually in the past? Probably. Do I have mixed feelings about skipping doing this manually? Yeah. It’s weird. I don’t worry when I skip other things because of UIs. I don’t feel the need to hand code each Sheets function or do the math behind photo manipulations. That doesn’t feel like cheating. It’s strange and I need to think about it more.


add_filter('comment_text', 'add_reply_as_user_dropdown', 10, 2);
function add_reply_as_user_dropdown($comment_text, $comment) {
    if (!current_user_can('moderate_comments')) return $comment_text;

    $users = get_users(['fields' => ['ID', 'display_name']]);
    ob_start();
    ?>
    <div class="reply-as-user-tools" data-comment-id="<?php echo $comment->comment_ID; ?>">
        <label for="reply-user-<?php echo $comment->comment_ID; ?>">Reply as:</label>
        <select class="reply-as-user-select" id="reply-user-<?php echo $comment->comment_ID; ?>">
            <option value="">Select user</option>
            <?php foreach ($users as $user): ?>
                <option value="<?php echo $user->ID; ?>"><?php echo esc_html($user->display_name); ?></option>
            <?php endforeach; ?>
        </select>
        <button class="reply-as-user-button" data-comment-id="<?php echo $comment->comment_ID; ?>">Reply</button>
    </div>
    <?php
    return $comment_text . ob_get_clean();
}


add_action('wp_ajax_reply_as_user', 'handle_reply_as_user');
function handle_reply_as_user() {
    if (!current_user_can('moderate_comments')) {
        wp_send_json_error('Permission denied');
    }

    $parent_id = intval($_POST['comment_id']);
    $user_id = intval($_POST['user_id']);

    $user = get_user_by('ID', $user_id);
    $parent = get_comment($parent_id);
    $apiKey = get_field('open_ai_key', 'option');

    if (!$user || !$parent || empty($apiKey)) {
        wp_send_json_error('Invalid user, comment, or API key.');
    }

    $generated_comment = generate_ai_comment($parent->comment_post_ID, $user_id, $apiKey, $parent_id);

    if (empty($generated_comment)) {
        wp_send_json_error('AI comment generation failed.');
    }

    wp_insert_comment([
        'comment_post_ID' => $parent->comment_post_ID,
        'comment_author' => $user->display_name,
        'comment_author_email' => $user->user_email,
        'comment_author_url' => $user->user_url,
        'comment_content' => $generated_comment,
        'user_id' => $user_id,
        'comment_parent' => $parent_id,
        'comment_approved' => 1,
    ]);

    wp_send_json_success('Reply posted');
}

document.addEventListener('DOMContentLoaded', function () {
    document.querySelectorAll('.reply-as-user-button').forEach(button => {
        button.addEventListener('click', function () {
            const commentId = this.dataset.commentId;
            const select = document.getElementById(`reply-user-${commentId}`);
            const userId = select.value;

            if (!userId) {
                alert('Please select a user.');
                return;
            }

            fetch(maddenessAjax.ajaxurl, {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: new URLSearchParams({
                    action: 'reply_as_user',
                    comment_id: commentId,
                    user_id: userId
                })
            })
            .then(res => res.json())
            .then(data => {
                if (data.success) {
                    alert('Reply posted.');
                    location.reload(); // or dynamically insert it into the DOM
                } else {
                    alert('Error: ' + data.data);
                }
            });
        });
    });
});

Options

It’s wild to see how far this could be taken. I’m just messing around but with some effort and solid programmers, you could easily create long-term personas that create content on all kinds of platforms in automated ways.


1 A semi-made up story.

2 And now I’m stuck worrying about this.

7 thoughts on “AI Commenting Chaos Incarnate”

  1. How did I miss you had a dozen kids? For some reason the only one of your examples I could not remember was Edupumkin. Gold!

  2. How hard did you loke for that Roy Rogers GIF?
    https://bavatuesdays.com/at-least-its-an-ethos/

    Also:
    Kid 7: Was he the one you worked on the “swamp of knowledge” Edtech Survivalist video? https://bavatuesdays.com/edtech-survivalist-episode-1/
    Kid 8: That guy who played Colonel Sam Troutman to your Johnny Rambo to that other Edtech Survialist? (the real lost gold)
    Kid 9: The one who you teamed up with to flame throw all the zombies in second life? https://bavatuesdays.com/mother-trucking-zombies/
    Kid 10: Oh, non-programmistan Jim? https://bavatuesdays.com/greetings-from-non-programistan/
    Kid 11: The educational insurance salesman to your hackie sack hippie? https://bavatuesdays.com/uncanny-edtech/

    It’s a long list, my friend, and the fact. you now have ridiculous programming chops to make the insanity happen in just a few short hours is pretty crazy. Kudos to you for not just entertaining another ridiculous idea, but also being able to make some sophisticated automation of a fake media universe happen so seamlessly

  3. I did leave a comment, but the number of links i used tripped the WordPress sentries thinking I might be a bot, the irony!

Comments are closed.