banner
段先森

三无青年

己所不欲,勿施于人
telegram
twitter
follow
email

Creating a Custom Reader Wall Feature in WordPress

Preface#

While browsing the Bu Yi Le Hu Blog, I was deeply attracted by the style of the reader wall on its message page. Additionally, I also saw a unique style on the wys friendly link page, which made me eager to try it out. So, I started searching online for related information and accidentally discovered a plugin previously written by Zhang Ge Blog. Although this plugin is no longer applicable due to its age, I decided to modify its code and implement it on my own blog.

Steps#

  • Add code to functions.php

First, find and open the functions.php file in your blog's theme directory. Then, add the following code to the end of the file:

// Register and load the CSS style for the readers wall
function enqueue_readers_wall_styles() {
    global $post;
    if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'readers_wall')) {
        wp_enqueue_style('readers-wall-style', get_template_directory_uri() . '/css/readers-wall.css', array(), '1.0.0');
    }
}
add_action('wp_enqueue_scripts', 'enqueue_readers_wall_styles');

// Helper function: Generate ranking list
function generate_readers_list($title, $query, $limit) {
    global $wpdb;
    $output = '';

    // Use transient cache for query results
    $transient_key = 'readers_wall_' . md5($query);
    $wall = get_transient($transient_key);

    if (false === $wall) {
        $wall = $wpdb->get_results($query);
        set_transient($transient_key, $wall, 3600);
    }

    $output .= '<div class="readers-section">';
    $output .= '<h2 class="entry-title">' . esc_html($title) . ' TOP' . esc_html($limit) . '</h2>';

    if ($wall) {
        $output .= "<ul class='readers-list'>";
        foreach ($wall as $comment) {
            $avatar = get_avatar($comment->comment_author_email, 64, '', '', array('loading' => 'lazy'));
            $url = esc_url($comment->comment_author_url ? $comment->comment_author_url : "#");
            $author = esc_html($comment->comment_author);
            $count = intval($comment->cnt);
            // Use author name instead of email as tooltip ID
            $tooltip_id = sanitize_title($author);

            $tooltip = "{$author}<br>Number of comments: {$count}";

            $output .= "<li>
                            <a rel='friend' target='_blank' href='{$url}' aria-describedby='tooltip-{$tooltip_id}'>
                                {$avatar}
                                <div class='tooltip' id='tooltip-{$tooltip_id}' role='tooltip'>{$tooltip}</div>
                            </a>
                        </li>";
        }
        $output .= "</ul>";
    } else {
        $output .= "<p>No data found for " . esc_html($title) . ".</p>";
    }

    $output .= '</div>';

    return $output;
}

// Shortcode function: Readers wall
function readers_wall_shortcode() {
    global $wpdb;
    $output = '';

    // Overall comment ranking
    $query2 = $wpdb->prepare(
        "SELECT COUNT(comment_ID) AS cnt, comment_author, comment_author_url, comment_author_email 
        FROM $wpdb->comments 
        LEFT JOIN $wpdb->posts ON ($wpdb->posts.ID = $wpdb->comments.comment_post_ID) 
        WHERE post_password = '' 
        AND comment_approved = '1' 
        AND comment_author != %s 
        GROUP BY comment_author_email 
        ORDER BY cnt DESC 
        LIMIT %d",
        'Mr. Duan',
        12
    );
    $output .= generate_readers_list('Overall Comment Ranking', $query2, 12);

    // Annual comment ranking
    $query1 = $wpdb->prepare(
        "SELECT COUNT(comment_ID) AS cnt, comment_author, comment_author_url, comment_author_email 
        FROM (
            SELECT * FROM $wpdb->comments 
            LEFT JOIN $wpdb->posts ON ($wpdb->posts.ID = $wpdb->comments.comment_post_ID) 
            WHERE comment_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 YEAR) AND NOW() 
            AND post_password = '' 
            AND comment_approved = '1'
            AND comment_author != %s
        ) AS tempcmt 
        GROUP BY comment_author_email 
        ORDER BY cnt DESC 
        LIMIT %d",
        'Mr. Duan',
        365
    );
    $output .= generate_readers_list('Annual Comment Ranking', $query1, 365);

    // Monthly comment ranking
    $query2 = $wpdb->prepare(
        "SELECT COUNT(comment_ID) AS cnt, comment_author, comment_author_url, comment_author_email 
        FROM (
            SELECT * FROM $wpdb->comments 
            LEFT JOIN $wpdb->posts ON ($wpdb->posts.ID = $wpdb->comments.comment_post_ID) 
            WHERE DATE_FORMAT(comment_date, '%%Y-%%m') = DATE_FORMAT(NOW(), '%%Y-%%m') 
            AND post_password = '' 
            AND comment_approved = '1'
            AND comment_author != %s
        ) AS tempcmt 
        GROUP BY comment_author_email 
        ORDER BY cnt DESC 
        LIMIT %d",
        'Mr. Duan',
        31
    );
    $output .= generate_readers_list('Monthly Comment Ranking', $query2, 31);

    // Weekly comment ranking
    $query3 = $wpdb->prepare(
        "SELECT COUNT(comment_ID) AS cnt, comment_author, comment_author_url, comment_author_email 
        FROM (
            SELECT * FROM $wpdb->comments 
            LEFT JOIN $wpdb->posts ON ($wpdb->posts.ID = $wpdb->comments.comment_post_ID) 
            WHERE YEARWEEK(DATE_FORMAT(comment_date, '%%Y-%%m-%%d')) = YEARWEEK(NOW()) 
            AND post_password = '' 
            AND comment_approved = '1'
            AND comment_author != %s
        ) AS tempcmt 
        GROUP BY comment_author_email 
        ORDER BY cnt DESC 
        LIMIT %d",
        'Mr. Duan',
        7
    );
    $output .= generate_readers_list('Weekly Comment Ranking', $query3, 7);

    return $output;
}
add_shortcode('readers_wall', 'readers_wall_shortcode');
  • Create CSS file

In your theme directory, find the css folder and create a new file named readers-wall.css. Paste the following style code into that file:

/* readers-wall.css */

/* Container styles */
.readers-section {
    margin-bottom: 30px;
}
.readers-section h2.entry-title {
    font-size: 24px;
    margin-bottom: 15px;
    color: #333;
}

/* Avatar list styles */
.readers-list { 
    display: flex; 
    flex-wrap: wrap; 
    list-style: none; 
    padding: 0;
    margin: 0;
}
.readers-list li {
    position: relative;
    margin: 10px;
    width: 50px; /* Adjust avatar size */
    height: 50px;
}
.readers-list li a {
    display: block;
    width: 100%;
    height: 100%;
    text-align: center;
    text-decoration: none;
    position: relative;
}
.readers-list li img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease;
}
.readers-list li a:hover img,
.readers-list li a:focus img {
    transform: scale(1.1);
}

/* Hover information box styles */
.readers-list li .tooltip {
    visibility: hidden;
    opacity: 0;
    width: 160px;
    background-color: rgba(0, 0, 0, 0.75);
    color: #fff;
    text-align: center;
    border-radius: 6px;
    padding: 8px;
    position: absolute;
    bottom: 60px; /* Above the avatar */
    left: 50%;
    transform: translateX(-50%);
    transition: opacity 0.3s ease;
    z-index: 10;
    font-size: 14px;
}
.readers-list li .tooltip::after {
    content: "";
    position: absolute;
    top: 100%; /* Arrow pointing to the avatar */
    left: 50%;
    margin-left: -5px;
    border-width: 5px;
    border-style: solid;
    border-color: rgba(0, 0, 0, 0.75) transparent transparent transparent;
}
.readers-list li:hover .tooltip,
.readers-list li a:focus .tooltip {
    visibility: visible;
    opacity: 1;
}

/* Responsive design */
@media (max-width: 600px) {
    .readers-list li {
        width: 40px;
        height: 40px;
    }
    .readers-section h2.entry-title {
        font-size: 20px;
    }
    .readers-list li .tooltip {
        width: 140px;
        font-size: 12px;
    }
}
  • Create a page and insert shortcode

In your WordPress backend, create a new page or edit an existing page, and insert the following shortcode:
readers_wall

image

Conclusion#

The above is the process I followed to implement a custom readers wall feature on my personal blog. If you wish to adjust the styles according to your needs, feel free to modify the CSS code in readers-wall.css.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.