How do I add <div> tags to entire comments, not just their text

Thanks to some wonderful help here at stack exchange, I have built a comment section with a dropdown menu that adds comment_meta to the comments.

I currently have a working filter that uses GET to trigger an if statement to query based on this comment_meta info. The thing I don't like is that it refreshes the page each time you click a button. I'm looking for a way to filter without having the page refresh. I think I need Javascript for this.

I've set up two sets of buttons. The top row is my GET buttons, which work, but refresh the page. The bottom row are my javascript buttons. I can get them to filter the text WITHIN the comments, but I'd like them to filter the entire contents instead.

For instance, if you go to Madonna's page (https://staging3.recordcollectorsoftheworldunite.com/artist/madonna/), and scroll down to the comments, they don't even show up until you press 'show all'. Once you press Show All it looks right, but again when you filter, it only filters the comments.

I've added 3 photos to the bottom of this post.

-First photo is when the page loads, how all the comments are hidden- I'd like ALL to automatically be selected when the page loads. I tried button class='button active' but that must not be the right way to say it.

-Second photo is when SHOW ALL is clicked

-Third photo is when BUY is clicked.

Here's my comments.php

?php
comment_form();
if (have_comments()) : ?
    div class=container
        div class=btn-group flex
            button type=button onclick=window.location.href='?php echo the_permalink();?/?cmeta=ALL'SHOW ALL/button
            button type=button onclick=window.location.href='?php echo the_permalink();?/?cmeta=BUY'BUY/button
            button type=button onclick=window.location.href='?php echo the_permalink();?/?cmeta=SELL'SELL/button
            button type=button onclick=window.location.href='?php echo the_permalink();?/?cmeta=TRADE'TRADE/button  
            button type=button onclick=window.location.href='?php echo the_permalink();?/?cmeta=TALK'TALK/button  
        /div  
    /div
    hr
    div class=container
        div class=btn-group flex
            button class=button active onclick=filterSelection('all') Show all/button
            button class=button onclick=filterSelection('BUY') BUY/button
            button class=button onclick=filterSelection('SELL') SELL/button
            button class=button onclick=filterSelection('TRADE') TRADE/button
            button class=button onclick=filterSelection('TALK') TALK/button
        /div  
    /div
    style
    .filterDiv {
    
    display: none;
    }

    .show {
    display: block;
    }

    .container {
    margin-top: 20px;
    overflow: hidden;
    }

    /style
    script
    filterSelection(all)
    function filterSelection(c) {
    var x, i;
    x = document.getElementsByClassName(filterDiv);
    if (c == all) c = ;
    // Add the show class (display:block) to the filtered elements, and remove the show class from the elements that are not selected
    for (i = 0; i  x.length; i++) {
        w3RemoveClass(x[i], show);
        if (x[i].className.indexOf(c)  -1) w3AddClass(x[i], show);
    }
    }

    // Show filtered elements
    function w3AddClass(element, name) {
    var i, arr1, arr2;
    arr1 = element.className.split( );
    arr2 = name.split( );
    for (i = 0; i  arr2.length; i++) {
        if (arr1.indexOf(arr2[i]) == -1) {
        element.className +=   + arr2[i];
        }
    }
    }

    // Hide elements that are not selected
    function w3RemoveClass(element, name) {
    var i, arr1, arr2;
    arr1 = element.className.split( );
    arr2 = name.split( );
    for (i = 0; i  arr2.length; i++) {
        while (arr1.indexOf(arr2[i])  -1) {
        arr1.splice(arr1.indexOf(arr2[i]), 1);
        }
    }
    element.className = arr1.join( );
    }

    // Add active class to the current control button (highlight it)
    var btnContainer = document.getElementById(myBtnContainer);
    var btns = btnContainer.getElementsByClassName(btn);
    for (var i = 0; i  btns.length; i++) {
    btns[i].addEventListener(click, function() {
        var current = document.getElementsByClassName(active);
        current[0].className = current[0].className.replace( active, );
        this.className +=  active;
    });
    }
    /script
    ?php
    if(isset($_GET['cmeta'])){
    
        $commentmeta=$_GET['cmeta'];
        if($commentmeta=='ALL'){
            $wantto= get_comment_meta( $comment_id, 'wantto', true );
            $args = array(
            'post_id' = get_the_ID(),
            
        );
        }else{
            $wantto= get_comment_meta( $comment_id, 'wantto', true );
            $args = array(
            'post_id' = get_the_ID(),
            'meta_query' = array(
            
                array(
                    'key' = 'wantto',
                    'value' = $commentmeta,
                ),
                
            )
        );
        }
        $comment_query = new WP_Comment_Query( $args );
        $comments = $comment_query-comments;
            echo 'ol class=post-comments';
                wp_list_comments(array(
                    'style'       = 'ol',
                    'short_ping'  = true,
                ));
                echo $wantto;
                
        echo '/ol';
        /* much simpler one to style probably
                        if ( $comments ) {
                    foreach ( $comments as $comment ) {
                        echo 'p' . $comment-comment_content . '/p';
                    }
                } else {
                    echo 'No comments found.';
                }
        */
    }else{

        $wantto= get_comment_meta( $comment_id, 'wantto', true );
        echo 'ol class=post-comments';
                wp_list_comments(array(
                    'style'       = 'ol',
                    'short_ping'  = true,
                ));
                echo $wantto;
                
        echo '/ol';
    }
endif;
    $comment_id=get_comment_ID();
    echo $wantto;
    
?

Here's the section from my functions.php that adds the dropdown menu, and filters by type. I've added the filterDiv tag in the second function of this part. Where I have it now only filters the text, I'd like it to filter the entire comment itself.


/*
 * This will add the fields to the comment form
*/
function wpse406058_custom_comment_fields() {

    echo 'p class=comment-form-wantto';
    echo 'label for=wanttoTag your comment so other users can find your post.brI want to/label';
    echo 'select id=wantto name=wantto class=myclass';
        echo 'option value=------/option';
        echo 'option value=BUYBUY/option';
        echo 'option value=SELLSELL/option';
        echo 'option value=TRADETRADE/option';
        echo 'option value=TALKTALK/option';
    echo '/select';
  
      
}
add_action( 'comment_form_logged_in_after', 'wpse406058_custom_comment_fields' );
add_action( 'comment_form_after_fields', 'wpse406058_custom_comment_fields' );

/*
 * This will field value as comment meta
*/
function wpse406058_save_custom_field($comment_id) {

    if ( isset($_POST['wantto'])  !empty($_POST['wantto']) ) {
        $wantto = sanitize_text_field($_POST['wantto']);
        update_comment_meta( $comment_id, 'wantto', $wantto );
        
    }
    
}
add_action( 'comment_post', 'wpse406058_save_custom_field' );


function wpse406058_display_comment_meta( $comment_text ) {
    
    $wantto = get_comment_meta( get_comment_ID(), 'wantto', true );
  
    if ( isset($wantto)  !empty($wantto) ) {
        
        $wanttotext = 'p class=wantosecI want to ' . esc_html($wantto) . '/p';
        ?div class=filterDiv ?php echo $wantto;??php
        $comment_text = $wanttotext . $comment_text;
    }
   echo 'div class=container';
    return $comment_text;
    echo '/div';
    echo '/div';
}
add_filter( 'comment_text', 'wpse406058_display_comment_meta' );

Topic comment-meta filters comments Wordpress javascript

Category Web


Currently your comment markup looks similar to the following:

<li class="comment byuser comment-author-rcotwunite odd alt thread-odd thread-alt depth-1" id="comment-7902">
  <div id="div-comment-7902" class="comment-body">
    <div class="comment-author vcard"><!-- ... --></div>
    <div class="comment-meta commentmetadata"><!-- ... --></div>
    <div class="filterDiv SELL show">
      <div class="container">
        <p class="wantosec">I want to SELL</p>
        <p>SUP YALL im here to sell some stuff</p>
        <div class="reply"><!-- ... --></div>
      </div>
    </div>
  </div>
</li>

And the JS which is targeting elements to show/hide:

function filterSelection(c) {
  var x, i;
  x = document.getElementsByClassName("filterDiv");

  if (c == "all") c = "";
  
  // Add the "show" class (display:block) to the filtered elements, and remove the "show" class from the elements that are not selected
  for (i = 0; i < x.length; i++) {
    w3RemoveClass(x[i], "show");
    if (x[i].className.indexOf(c) > -1) w3AddClass(x[i], "show");
  }
}

So the issue is that the class you're using to target elements to show/hide is only applied to a descendant child of the element which represents the full comment (the <li> encapsulating the whole entry, here).


JS DOM Traversal

One solution to targeting that encapsulating <li> instead would be to keep the markup as it is and use the properties on DOM elements to traverse up to the ancestral <li> (though this isn't terribly efficient):

function filterSelection(c) {
  var x, i;
  x = document.getElementsByClassName("filterDiv");

  if (c == "all") c = "";
  
  // Add the "show" class (display:block) to the filtered elements, and remove the "show" class from the elements that are not selected
  for (i = 0; i < x.length; i++) {
    w3RemoveClass(x[i].parentElement.parentElement, "show");
    if (x[i].parentElement.parentElement.className.indexOf(c) > -1) 
      w3AddClass(x[i].parentElement.parentElement, "show");
  }
}

Customize Comment Markup

But perhaps a better solution is to use wp_list_comments()'s callback argument to specify a function to customize each comment's generated markup and apply your HTML classes derived from comment meta-data to the entire comment container instead of just the body.

The best way to start might be to simply copy the function body over from the Walker_Comment::comment() method, which is otherwise responsible for rendering comment markup. And then we'll tweak it to add a couple classes to the containing element if your comment meta exists (I've added PHP comments to designate my modifications):

// functions.php

function wpse406332_render_comment( $comment, $args, $depth ) {
  if ( 'div' === $args['style'] ) {
        $tag       = 'div';
        $add_below = 'comment';
    } else {
        $tag       = 'li';
        $add_below = 'div-comment';
    }
 
    $commenter          = wp_get_current_commenter();
    $show_pending_links = isset( $commenter['comment_author'] ) && $commenter['comment_author'];

    // Set up an array to contain classes to be applied to the `<li>`.
    $classes = [];

    if( $this->has_children )
      array_push( $classes, 'parent' );

    // Check for trade meta
    $wantto = get_comment_meta( get_comment_ID(), 'wantto', true );

    // If trade meta is set, add "filterDiv" and trade type to class list.
    if ( isset($wantto) && !empty($wantto) )
      array_push( $classes, 'filterDiv', $wantto );
 
    if ( $commenter['comment_author_email'] ) {
        $moderation_note = __( 'Your comment is awaiting moderation.' );
    } else {
        $moderation_note = __( 'Your comment is awaiting moderation. This is a preview; your comment will be visible after it has been approved.' );
    }
    ?>

    // Finally, add our modified class list to the comment container.
    <<?php echo $tag; ?> <?php comment_class( $classes, $comment ); ?> id="comment-<?php comment_ID(); ?>">
    <?php if ( 'div' !== $args['style'] ) : ?>
    <div id="div-comment-<?php comment_ID(); ?>" class="comment-body">
    <?php endif; ?>
    <div class="comment-author vcard">
        <?php
        if ( 0 != $args['avatar_size'] ) {
            echo get_avatar( $comment, $args['avatar_size'] );
        }
        ?>
        <?php
        $comment_author = get_comment_author_link( $comment );
 
        if ( '0' == $comment->comment_approved && ! $show_pending_links ) {
            $comment_author = get_comment_author( $comment );
        }
 
        printf(
            /* translators: %s: Comment author link. */
            __( '%s <span class="says">says:</span>' ),
            sprintf( '<cite class="fn">%s</cite>', $comment_author )
        );
        ?>
    </div>
    <?php if ( '0' == $comment->comment_approved ) : ?>
    <em class="comment-awaiting-moderation"><?php echo $moderation_note; ?></em>
    <br />
    <?php endif; ?>
 
    <div class="comment-meta commentmetadata">
        <?php
        printf(
            '<a href="%s">%s</a>',
            esc_url( get_comment_link( $comment, $args ) ),
            sprintf(
                /* translators: 1: Comment date, 2: Comment time. */
                __( '%1$s at %2$s' ),
                get_comment_date( '', $comment ),
                get_comment_time()
            )
        );
 
        edit_comment_link( __( '(Edit)' ), ' &nbsp;&nbsp;', '' );
        ?>
    </div>
 
    <?php
    comment_text(
        $comment,
        array_merge(
            $args,
            array(
                'add_below' => $add_below,
                'depth'     => $depth,
                'max_depth' => $args['max_depth'],
            )
        )
    );
    ?>
 
    <?php
    comment_reply_link(
        array_merge(
            $args,
            array(
                'add_below' => $add_below,
                'depth'     => $depth,
                'max_depth' => $args['max_depth'],
                'before'    => '<div class="reply">',
                'after'     => '</div>',
            )
        )
    );
    ?>
 
    <?php if ( 'div' !== $args['style'] ) : ?>
    </div>
    <?php endif; ?>
    <?php
}

Now modify your wp_comment_list() calls to use the modified render function instead of Walker_Comment's (you'll also want to remove the code which adds those classes to the comment text container from your wpse406058_display_comment_meta() function):

// template file

// ...
wp_list_comments(array(
  'style'       => 'ol',
  'short_ping'  => true,
  'callback'    => 'wpse406332_render_comment',
));
// ...

Wrap-Up

This is by no means an exhaustive list of possibilities. Another solution which wouldn't include modifying the comment markup would be to build a mapping of trade types to <li> elements on page load (using that DOM traversal technique from above), then just referring to those arrays when you need to show/hide comments.

All in all I think customizing the comment markup is the most robust solution, and one which can enable you to further tweak the display for your unique comments use-case (though if your modifications eventually lead to a massive departure from the intent of a simple comment, you might at some point consider using a dedicated post-type for the purpose).

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.