Customizing WordPress comments

The documentation on customizing WordPress comments is a bit sparse, particularly when compared to WordPress posts. I ran into this issue while building a web application built off of WordPress and wanted to use WordPress’ commenting system with some custom fields and styling. So here’s my attempt to address that.

  1. Make sure you have a comments.php template file for your theme – create one if needed. I recommend looking at _s for a good model.
  2. See the following code below – it should be pretty obvious with its inline commenting. Please excuse any WordPress code formatting issues.
  3. With this code we can now wrap your comment markup with our own tags and classes as well as display our own custom comment fields/data using get_comment_meta().
  4. The WordPress core comment-template.php file had the clues I needed to figure this out. I saw how they were structuring and coding things so I translated that code into my comments.php theme file, tested, and tidied it up until it worked. Now to the code…
<?php
/*
 If the current post is protected by a password and
 the visitor has not yet entered the password we will
 return early without loading the comments.
 */
if ( post_password_required() ) {
    return;
}
?>
<?php // Now our comments area ?>
<div id="comments" class="comments-area">
    <?php //check to see if we have comments
    if ( have_comments() ) : ?>
        <h2 class="comments-title">
            <?php
                printf( // WPCS: XSS OK.
                    esc_html( _nx( 'One comment on &ldquo;%2$s&rdquo;', '%1$s comments on &ldquo;%2$s&rdquo;', get_comments_number(), 'comments title', '_s' ) ),
                    number_format_i18n( get_comments_number() ),
                    '<span>' . get_the_title() . '</span>'
                );
            ?>
        </h2>
    <?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // Are there comments to navigate through? ?>
        <nav id="comment-nav-above" class="navigation comment-navigation" role="navigation">
            <h2 class="screen-reader-text"><?php esc_html_e( 'Comment navigation', '_s' ); ?></h2>
            <div class="nav-links">
<?php //comment navigation links ?>

                <div class="nav-previous"><?php previous_comments_link( esc_html__( 'Older Comments', '_s' ) ); ?></div>
                <div class="nav-next"><?php next_comments_link( esc_html__( 'Newer Comments', '_s' ) ); ?></div>

            </div><!-- .nav-links -->
        </nav><!-- #comment-nav-above -->
        <?php endif; // Check for comment navigation. ?>

    <ol class="comment-list">
            <?php if ( have_comments() ) : //possibly duplicative, but this works ?>
            <?php while (have_comments() ) : the_comment(); //the loop, but for comments ?>
            <li id="comment-<?php comment_ID(); ?>" <?php comment_class(); ?>>
            <article id="div-comment-<?php comment_ID(); ?>" class="comment-body">
                <footer class="comment-meta">
                    <div class="comment-author vcard">
                        <?php echo get_avatar( $comment->comment_ID ); ?>
                        <?php printf( __( '%s <span class="says">says:</span>' ), sprintf( '<strong class="fn">%s</strong>', get_comment_author_link() ) ); ?>
                    </div><!-- .comment-author -->

                    <div class="comment-metadata">
                        <a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
                            <time datetime="<?php comment_time( 'c' ); ?>">
                                <?php printf( _x( '%1$s at %2$s', '1: date, 2: time' ), get_comment_date(), get_comment_time() ); ?>
                            </time>
                        </a>
                        <?php edit_comment_link( __( 'Edit' ), '<span class="edit-link">', '</span>' ); ?>
                    </div><!-- .comment-metadata -->

                    <?php if ( '0' == $comment->comment_approved ) : //is the comment in moderation ?>
                        <p class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.' ); ?></p>
                    <?php endif; ?>
                </footer><!-- .comment-meta -->

                <div class="comment-content">
                <?php
                comment_text(); //the actual comment content 
                ?>
                </div><!-- .comment-content -->

                <?php
                comment_reply_link(); // the reply to a comment link
                ?>
            </article><!-- .comment-body -->
            </li>
                        <?php endwhile; ?>
            <?php endif; //closing out our comment loop 
            ?>
        </ol><!-- .comment-list -->
    <?php
        // If comments are closed and there are comments, let's leave a little note, shall we?
        if ( ! comments_open() && get_comments_number() && post_type_supports( get_post_type(), 'comments' ) ) :
    ?>
        <p class="no-comments"><?php esc_html_e( 'Comments are closed.', '_s' ); ?></p>
    <?php endif; ?>

    <?php comment_form(); //the comment form ?>

</div><!-- #comments -->

A very useful WordPress code snippet to know…

As I was working on a custom WordPress theme (based on _s) I found myself trying to get the slug of a post to use as a class for additional styling. Unfortunately, WordPress doesn’t have a get_the_slug() function or a the_slug() function. Well, not built out like that at any rate. The “why not?” is basically because the global $post object contains that info and thus can be found already and no extra functions needed. And then I ran into this wonderful bit of code from TCBarret (code commenting is mine):

/*This function gets the slug of a post 
- you need this to use the next code snippet.
*/
function get_the_slug( $id=null ){
  if( empty($id) ):
    global $post;
    if( empty($post) )
      return ''; // No global $post var available.
    $id = $post->ID;
  endif;

  $slug = basename( get_permalink($id) );
  return $slug;
}

So again, the above code will get_the_slug();. Now to use it, we want a filter and echo out the filtered post ID as the_slug(). And that code is:

/*This adds a filter and allows us to display the results of the
get_the_slug() function noted above.
*/
function the_slug( $id=null ){
  echo apply_filters( 'the_slug', get_the_slug($id) );
}

How to use this? Well I decided to build out a little utility plugin which incorporates the above code so I can use it pretty much in any WordPress install – it’s not tied to a theme or what not. You can use the above code in a theme’s functions.php instead of a plugin but I think a plugin is a better choice as it means the functionality is usable across whatever theme you decide to use. Anyway, special thanks to TCBarret for his excellent (and very useful) code.

CPT-onomies

WordPress is great at providing a robust system for managing content. However, one of it’s pain points is trying to create a relationship between posts (i.e. post to post relationship). Yes there’s taxonomies but sometimes you really want to tie specific posts to other specific posts. This gets more complicated when you have three (or more) different post types that need to be related to each other. And each one of these post types need to relate to multiple individual posts of the other post types.

Enter the fantastic plugin CPT-onomies.

In a nutshell, CPT-onomies allows you to treat a post as a custom taxonomy, allowing you to link posts together as if each post title was a term in the custom taxonomy.

CPT-onomies also makes it easy to create and manage custom post types and does a great job of walking you through how this is actually done. It actually explains what the options are and how WordPress uses them. But you can create your CPTs (Custom Post Types) with other tools (or by hand) if you want and just let CPT-onomies do it’s magic. Another nice thing is that CPT-onomies follows, as much as possible, the existing structure of taxonomies within WordPress. Functions are nearly identical to the built-in taxonomy functions so its easy to incorporate in your templates.

So yeah – if you need to build out more complex relationships between posts, beyond the standard taxonomy relationships, take a look at CPT-onomies.