Bài viết hướng dẫn mở rộng tính năng bình luận bằng ảnh GIF (sử dụng Tenor) cho hệ thống bình luận mặc định của WordPress.

Bình luận bằng ảnh GIF trong hệ thống bình luận mặc định WordPress

Có nhiều hệ thống cung cấp ảnh GIF, các bạn có thể thấy trên Facebook. Ở đây mình chọn Tenor GIF Keyboard vì theo mình là dễ sử dụng. Bài viết sử dụng Bootstrap 3, phần Modal để hỗ trợ lựa chọn ảnh GIF và Glyphicons.

Bài viết này áp dụng cho Giao diện bình luận WordPress tiếng Việt đầy đủ của trang giới thiệu, các bạn có thể tham khảo.

Đăng ký Tenor

Các bạn vào Tenor GIF API, bấm vào nút Get a free API key.

Đi đến liên kết

Nếu chưa có tài khoản, hãy đăng ký và xác nhận email để được cung cấp API.

Đăng ký Tenor

Sau đó, bấm vào Create new app, tạo một ứng dụng mới, lưu ý chỉ sử dụng tiếng Anh hoặc tiếng Việt không dấu.

Create a new app - Tenor

Thêm Tenor vào WordPress

Xử lý Tenor

Tạo tập tin tenor.js với nội dung sau.

function httpGetAsync(theUrl, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function() {
        if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
            callback(xmlHttp.responseText);
        }
    }

    xmlHttp.open('GET', theUrl, true);
    xmlHttp.send(null);
    return;
}

function tenorCallbackSearch(responsetext) {
    var response_objects = JSON.parse(responsetext);
    top_10_gifs = response_objects['results'];

    if (top_10_gifs.length > 0) {
        for (var i = 0; i < top_10_gifs.length; i++) {
            $('.gif-list').append('<img class="search-gif-result" src="' + top_10_gifs[i]["media"][0]["tinygif"]["url"] + '" alt="Tenor GIF ' + i + '" data-id="' + top_10_gifs[i]["id"] + '" onclick="chooseGIF(this);">');
        }
    }
    
    return;
}

function grabGIF(type = 'trending', search_term = 'excited', lmt = 15) {
    var apikey = 'LIVDSRZULELA';
    var search_url = '';

    if (type == 'trending') search_url = 'https://api.tenor.com/v1/trending?key=' + apikey + '&limit=' + lmt;
    else if (type == 'random') search_url = 'https://api.tenor.com/v1/random?q=' + search_term + '&key=' + apikey + '&limit=' + lmt;
    else search_url = 'https://api.tenor.com/v1/search?q=' + search_term + '&key=' + apikey + '&limit=' + lmt;

    $('.gif-list').html('');
    httpGetAsync(search_url, tenorCallbackSearch);

    return;
}

Lưu ý: Thay var apikey = 'LIVDSRZULELA'; bằng API Key của bạn.

Tập tin trên cung cấp các kết nối tới Tenor và 3 phương thức lấy ảnh GIF: tìm kiếm ngẫu nhiên (random), xu hướng (trending) và tìm kiếm bình thường (search).

CSS

.tags {
    margin-bottom: 15px;
}

.tags a, a.tags-link {
    font-size: 13px;
    padding: 6px;
    line-height: 31px;
    background: #0faef1;
    color: #fff;
    white-space: nowrap;
}

.tags a:hover, a.tags-link:hover {
    background: #0d94cd;
}

.search-gif-result, .meme-img {
    display: block;
    margin-bottom: 15px;
    width: 100%;
    cursor: pointer;
}

.gif-container, .meme-cmt {
    max-width: 375px;
    display: flex;
}

#gif-search-btn {
    pointer-events: all;
    cursor: pointer;
}

#gif-search-btn:hover, #gif-search-btn:focus {
    color: #0faef1;
}

HTML

Mình sử dụng một Modal kích thước md để lựa chọn ảnh GIF.

<div class="modal fade" id="gif-modal" tabindex="-1" role="dialog">
    <div class="modal-dialog modal-md" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title">Tenor GIF</h4>
            </div>
            <div class="modal-body">
                <div class="form-group has-feedback list-search">
                    <input id="gif-search-input" type="text" class="form-control" placeholder="Tìm ảnh GIF...">
                    <span id="gif-search-btn" class="glyphicon glyphicon-search form-control-feedback"></span>
                </div>
                <div class="tags">
                    <a id="trending-gif" href="#">Xu Hướng</a>
                    <a id="funny-gif" href="#">Vui</a>
                    <a id="sad-gif" href="#">Buồn</a>
                    <a id="cat-gif" href="#">Mèo</a>
                    <a id="random-gif" href="#"><span class="glyphicon glyphicon-random"></span> Ngẫu Nhiên</a>
                </div>
                <div class="gif-list margin-bottom-15px">
                    <!-- Ảnh GIF ở đây -->
                </div>
                <div class="clearfix"></div>
            </div>
        </div>
    </div>
</div>

Ở cuối trang web, trước </body>, thêm một số đoạn mã xử lí việc thêm ảnh GIF. Trước tiên, chèn tenor.js vừa tạo ở trên (ở đây mình bỏ vào thư mục includes) và embed.js của Tenor.

<script src="<?php bloginfo('template_url'); ?>/includes/tenor.js"></script>
<script type="text/javascript" async src="https://tenor.com/embed.js"></script>

Thêm nút chọn ảnh GIF vào sau khung bình luận và chọn ảnh.

<script type="text/javascript">
    $('#commentform textarea#comment').after('Thêm <u>01</u> ảnh GIF: <span class="gif-button glyphicon glyphicon-film"></span>');

    $('.gif-button').click(function() {
        $('#gif-modal').modal();
        grabGIF('random', 'smile');
    });

    $('#gif-search-input').keypress(function() {
        var keycode = (event.keyCode ? event.keyCode : event.which);
        if (keycode == '13') {
            var searchTerm = $(this).val();
            if (searchTerm.length > 0) {
                grabGIF('search', searchTerm);
            } else {
                grabGIF();
            }
        }
    });

    $('#gif-search-btn').click(function() {
        var searchTerm = $('#gif-search-input').val();
        if (searchTerm.length > 0) {
            grabGIF('search', searchTerm);
        } else {
            grabGIF();
        }
    });

    $('#trending-gif').click(function(e) {
        e.preventDefault();
        grabGIF();
    });

    $('#random-gif').click(function(e) {
        e.preventDefault();
        var searchTerm = $('#gif-search-input').val();
        if (searchTerm.length > 0) {
            grabGIF('random', searchTerm);
        } else {
            grabGIF('random');
        }
    });

    $('#funny-gif').click(function(e) {
        e.preventDefault();
        grabGIF('random', 'funny');
    });

    $('#sad-gif').click(function(e) {
        e.preventDefault();
        grabGIF('random', 'sad');
    });

    $('#cat-gif').click(function(e) {
        e.preventDefault();
        grabGIF('random', 'cat');
    });

    function chooseGIF(img) {
        if (!$('textarea#comment').val().includes('ocm:')) {
            $('textarea#comment').val($('textarea#comment').val() + 'gif-ocm:' + $(img).data('id'));
        }
        $('#gif-modal').modal('hide');
    }

    $('div.comment-content').each(function() {
        if ($(this).find('div.gif-container').length > 1) {
            $(this).find('div.gif-container').slice(1, $(this).find('div.gif-container').length).remove();
        }
    });
</script>

Xử lý ở functions.php

// Comments Filter
add_filter('comment_text', 'ocm_filter_comment');
function ocm_filter_comment($comment) {
    $blog_url = get_bloginfo('url');
    $tem_url = get_bloginfo('template_url');

    if (strpos($comment, 'gif-ocm:') !== false) {
        $regex = '~(:\S+)~';
        $gif = [];
        if (preg_match_all($regex, $comment, $matches, PREG_PATTERN_ORDER)) {
               foreach ($matches[1] as $word) {
                   if (strlen($word) > 4) {
                       array_push($gif, $word);
                       $comment = str_replace($word, '', $comment);
                   }
               }
               $comment = str_replace('gif-ocm', '', $comment);
        }
        if (count($gif) > 0) {
            $gif = explode(':', $gif[0]);
            if (is_numeric($gif[1])) $comment .= '<div class="gif-container tenor-gif-embed" data-postid="' . $gif[1] . '" data-share-method="host" data-width="100%" data-aspect-ratio="1.45"></div>';
        }
    }

    return $comment;
}

Vậy là đã xong rồi, các bạn có thể thử nghiệm ở Localhost trước khi triển khai lên dự án của mình nhé!

Tổng kết

Cách làm trên vẫn còn một vài khuyết điểm, ví dụ bình luận sai cú pháp sẽ không thể xử lí, và chỉ xuất hình đc ở tỉ lệ 1.45 (thông số ở data-aspect-ratio, bạn có thể tùy chỉnh tùy ý) mà không thể biết chính xác tỉ lệ của từng hình (vì mình không thấy Tenor cung cấp ở API). Trong tương lai có thể cải thiện thêm, chúc các bạn thành công!