Sử dụng AJAX trong WordPress

AJAX là chữ viết tắt của cụm từ Asynchronous Javascript and XML. AJAX là phương thức trao đổi dữ liệu với máy chủ và cập nhật một hay nhiều phần của trang web, hoàn toàn không reload lại toàn bộ trang.

AJAX được viết bằng Javascript chạy trên client, tức là mỗi browser sẽ chạy độc lập hoàn toàn không ảnh hưởng lẫn nhau. Về mặt kỹ thuật, nó đề cập đến việc sử dụng các đối tượng XmlHttpRequest để tương tác với một máy chủ web thông qua Javascript.

$.ajax({
    type: "GET",
    dataType: "json",
    url: "wp-admin/admin-ajax.php",
    data: {
        action: "lai_dinh_cuong_ajax"
    },
    success: function (response) {
        console.log(response);
    }
});

AJAX là một trong những công cụ giúp chúng ta đem lại cho người dùng trải nghiệm tốt hơn. Khi cần một thay đổi nhỏ thì sẽ không cần load lại cả trang web, làm trang web phải tải lại nhiều thứ không cần thiết.

let ajaxSearch = function () {
    let http,
        cache = [],
        textInput = BODY.find("input[data-xf-init='auto-complete']"),
        timeout = null,
        results = null;

    if (window.XMLHttpRequest) {
        http = new XMLHttpRequest();
    } else {
        http = new ActiveXObject("Microsoft.XMLHTTP");
    }

    $(document).click(function (event) {
        let target = $(event.target),
            results = target.closest(".search-results");

        if (!results || !results.length) {
            $(".search-results").hide();
        }
    });

    BODY.on("click", ".live-search-container .search-results > *", function (e) {
        e.preventDefault();
        let that = this,
            element = $(that),
            container = element.parent(),
            input = container.prev("input");

        container.children().removeClass("is-selected");
        element.addClass("is-selected");
        input.val(element.attr("data-user-name"));
        container.hide();
    });

    function process(search) {
        let interval = setInterval(function () {
            if (http.responseText !== "" || (http.readyState === 4 && http.status === 200)) {
                results.html(http.responseText).show();
                clearInterval(interval);
                cache[search] = http.responseText;
            }
        }, 100);
    }

    textInput.on("keyup", function () {
        liveSearch(this);
    });

    textInput.on("focus click mousedown", function () {
        if (results && results.length) {
            results.hide();
        }
    });

    function liveSearch(element) {
        clearTimeout(timeout);
        let that = element,
            search = that.value;

        element = $(element);
        results = element.parent().find(".search-results");

        if (results && results.length) {
            results.hide();
        }

        if (search.length > 1) {
            timeout = setTimeout(function () {
                if (search in cache) {
                    results.html(cache[search]).show();
                } else {
                    process(search);
                    http.open("GET", GB_FRONTEND.ajaxUrl + "?action=group_buy&do_action=live_search&name=" + that.name + "&data=" + search, true);
                    http.send();
                }
            }, 100);
        } else {
            results.html("").hide();
        }
    }
};

Bên trên là đoạn code ví dụ áp dụng cho live search. Khi gõ từ khóa vào ô tìm kiếm, hệ thống sẽ thực thi AJAX tìm kiếm trong dữ liệu và hiển thị danh sách kết quả gợi ý lên cho người dùng chọn.

jQuery(document).ready(function ($) {
    var body = $("body");

    function hocwp_theme_remove_file_preview(filePreview, inputFile, fesFile, key) {
        filePreview.on("click", ".dz-remove", function (e) {
            e.preventDefault();
            e.stopPropagation();
            inputFile.val(null);
            inputFile.trigger("change");

            if (confirm(pixelify.text.are_you_sure)) {
                var postID = parseInt(filePreview.attr("data-post-id"));

                if (!$.isNumeric(postID)) {
                    postID = parseInt(fesFile.attr("data-post-id"));
                }

                key = key || "font_demos";

                $.ajax({
                    type: "POST",
                    dataType: "JSON",
                    url: pixelify.ajaxUrl,
                    cache: true,
                    data: {
                        action: "hocwp_pxf_remove_file",
                        id: filePreview.attr("data-id"),
                        post_id: postID,
                        key: key
                    },
                    success: function () {
                        filePreview.removeClass("dz-error");
                        filePreview.removeClass("dz-complete");
                        filePreview.removeClass("dz-processing");
                        filePreview.removeClass("has-media");
                        filePreview.attr("data-id", "");
                        filePreview.find("input.media-id").val();

                        var thumbs = fesFile.find(".dz-preview.has-media");

                        if (!thumbs.length) {
                            fesFile.removeClass("has-media");
                        } else {
                            fesFile.addClass("has-media");
                        }

                        fesFile.find(".dz-message").show();

                        filePreview.remove();
                    }
                });
            }
        });
    }

    // Sliders upload
    (function () {
        var fesFile = $("#fes-zf_fes_featured_images"),
            inputFile = fesFile.find("#product-images"),
            dzLabel = fesFile.find(".dz-default.dz-message"),
            myForm = inputFile.closest("form");

        if (myForm.hasClass("image-set")) {
            Cookies.remove("forum_images");
            myForm.removeClass("image-set");
        }

        let forumImages = Cookies.get("forum_images");

        if (forumImages) {
            forumImages = JSON.stringify(forumImages);
        }

        if ("undefined" === typeof forumImages) {
            forumImages = [];
        }

        if (forumImages.length) {
            myForm.find("input[name='tmp_images']").val(Cookies.get("forum_images"));
        }

        dzLabel.on("click", function (e) {
            e.preventDefault();
            e.stopPropagation();

            inputFile.trigger("click");
        });

        fesFile.find(".dz-preview.has-image").each(function () {
            hocwp_theme_remove_image_preview($(this), inputFile, fesFile, null, dzLabel);
        });

        function hocwp_theme_remove_image_preview(imagePreview, inputFile, fesFile, maxImage, dzLabel) {
            imagePreview.on("click", ".dz-remove", function (e) {
                e.preventDefault();
                e.stopPropagation();
                inputFile.val(null);
                inputFile.trigger("change");

                if (confirm(pixelify.text.are_you_sure)) {
                    maxImage = maxImage || parseInt(inputFile.attr("data-max"));

                    var postID = parseInt(imagePreview.attr("data-post-id"));

                    if (!$.isNumeric(postID)) {
                        postID = parseInt(fesFile.attr("data-post-id"));
                    }

                    let removeID = parseInt(imagePreview.attr("data-id"));

                    $.ajax({
                        type: "POST",
                        dataType: "JSON",
                        url: pixelify.ajaxUrl,
                        cache: true,
                        data: {
                            action: "hocwp_pxf_remove_file",
                            id: removeID,
                            post_id: postID,
                            tmp_images: forumImages
                        },
                        success: function (response) {
                            forumImages = response.data.tmp_images;

                            if ("object" === typeof forumImages) {
                                let index = forumImages.indexOf(removeID);

                                if (index !== -1) {
                                    forumImages.splice(index, 1);
                                }
                            }

                            if (forumImages && forumImages.length) {
                                Cookies.set("forum_images", JSON.stringify(forumImages));
                                myForm.find("input[name='tmp_images']").val(Cookies.get("forum_images"));
                            } else {
                                Cookies.remove("forum_images");
                                myForm.find("input[name='tmp_images']").val("");
                            }

                            imagePreview.removeClass("dz-error");
                            imagePreview.removeClass("dz-complete");
                            imagePreview.removeClass("dz-processing");
                            imagePreview.removeClass("has-image");
                            imagePreview.attr("data-id", "");
                            imagePreview.find("input.media-id").val();

                            var thumbs = fesFile.find(".dz-preview.has-image");

                            if (!thumbs.length) {
                                fesFile.removeClass("has-image");
                            } else {
                                fesFile.addClass("has-image");
                            }

                            imagePreview.remove();

                            var previews = fesFile.find(".dz-preview");

                            if (!previews.length) {
                                fesFile.append(pixelify.imagePreview);
                            }

                            if (thumbs.length < maxImage) {
                                dzLabel.show();
                            } else {
                                dzLabel.hide();
                            }
                        }
                    });
                }
            });
        }

        inputFile.on("uploadFile", function () {
            var maxImage = parseInt(inputFile.attr("data-max")),
                thumbs = fesFile.find(".dz-preview.has-image");

            var files = inputFile[0].files,
                i = 0,
                count = files.length,
                maxSize = parseFloat(inputFile.attr("data-max-size"));

            //dzLabel.hide();

            for (i; i < count; i++) {
                var file = files[i];

                if (file) {
                    if (file.size > (maxSize * 1024 * 1024)) {
                        inputFile.val(null);
                        inputFile.trigger("change");

                        return;
                    }

                    (function (file) {
                        var imagePreview = fesFile.find("div.dz-preview:not(.has-image):not(.dz-processing)").first();

                        if (!imagePreview.length) {
                            //fesFile.append(pixelify.imagePreview);
                            //imagePreview = fesFile.find("div.dz-preview:not(.has-image):not(.dz-processing)").first();
                        }

                        imagePreview.addClass("dz-processing");

                        var Upload = function (file) {
                            this.file = file;
                        };

                        Upload.prototype.getType = function () {
                            return this.file.type;
                        };

                        Upload.prototype.getSize = function () {
                            return this.file.size;
                        };

                        Upload.prototype.getName = function () {
                            return this.file.name;
                        };

                        Upload.prototype.doUpload = function () {
                            var that = this;
                            var formData = new FormData();

                            // add assoc key values, this will be posts values
                            formData.append("file", this.file);
                            formData.append("upload_file", true);
                            formData.append("accept", inputFile.attr("accept"));

                            var postID = parseInt(fesFile.attr("data-post-id"));

                            $.ajax({
                                type: "POST",
                                url: pixelify.ajaxUrl + "?action=hocwp_pxf_upload_file&post_id=" + postID,
                                xhr: function () {
                                    var myXhr = $.ajaxSettings.xhr();

                                    if (myXhr.upload) {
                                        myXhr.upload.addEventListener("progress", that.progressHandling, false);
                                    }

                                    return myXhr;
                                },
                                success: function (response) {
                                    // your callback here
                                    imagePreview.removeClass("dz-processing");
                                    imagePreview.addClass("dz-complete");

                                    if (response.success) {
                                        if (response.data.id) {
                                            if (-1 === $.inArray(response.data.id, forumImages)) {
                                                forumImages.push(response.data.id);
                                            }

                                            Cookies.set("forum_images", JSON.stringify(forumImages));
                                            myForm.find("input[name='tmp_images']").val(Cookies.get("forum_images"));

                                            imagePreview.attr("data-id", response.data.id);
                                            imagePreview.find("input.media-id").val(response.data.id);
                                            imagePreview.addClass("has-image");
                                            fesFile.addClass("has-image");
                                            imagePreview.removeClass("dz-processing");

                                            let thumbs = fesFile.find(".dz-preview.has-image");

                                            if (count < maxImage && (!thumbs.length || (thumbs.length + 1) <= maxImage)) {
                                                dzLabel.show();
                                            } else {
                                                dzLabel.hide();
                                            }

                                            inputFile.trigger("uploadCompleted");
                                        }

                                        inputFile.val(null);
                                    } else {
                                        imagePreview.remove();

                                        var previews = fesFile.find(".dz-preview");

                                        if (!previews.length) {
                                            fesFile.removeClass("has-image");
                                            dzLabel.show();
                                        }

                                        if (response.data.message) {
                                            alert(response.data.message);
                                        }
                                    }
                                },
                                error: function (error) {
                                    // handle error
                                },
                                async: true,
                                data: formData,
                                cache: false,
                                contentType: false,
                                processData: false,
                                timeout: 60000
                            });
                        };

                        Upload.prototype.progressHandling = function (event) {
                            let percent = 0,
                                position = event.loaded || event.position,
                                total = event.total;

                            if (event.lengthComputable) {
                                percent = Math.ceil(position / total * 100);
                            }

                            let dzUpload = imagePreview.find(".dz-upload");

                            dzUpload.css({width: percent.toString() + "%"});

                            if (percent <= 100) {
                                imagePreview.addClass("dz-processing");
                            } else {
                                imagePreview.removeClass("dz-processing");
                            }
                        };

                        setTimeout(function () {
                            if (!imagePreview.hasClass("dz-error")) {
                                var upload = new Upload(file);

                                // maybe check size or type here with upload.getSize() and upload.getType()

                                // execute upload
                                upload.doUpload();
                            } else {
                                imagePreview.removeClass("dz-processing");
                            }
                        }, 2000);

                        var maxWidth = parseInt(inputFile.attr("data-max-width")),
                            maxHeight = parseInt(inputFile.attr("data-max-height"));

                        (function (maxWidth, maxHeight, imagePreview, file) {
                            var img = new Image();

                            img.src = window.URL.createObjectURL(file);

                            img.onload = function () {
                                var width = img.width,
                                    height = img.height;

                                window.URL.revokeObjectURL(img.src);

                                if (width > maxHeight || height > maxHeight) {
                                    imagePreview.removeClass("dz-processing");
                                    imagePreview.addClass("dz-error");
                                }
                            };

                            var reader = new FileReader();

                            reader.onload = function (e) {
                                imagePreview.find(".dz-image img").attr("src", e.target.result).show();
                                imagePreview.show();
                            };

                            reader.readAsDataURL(file);

                            hocwp_theme_remove_image_preview(imagePreview, inputFile, fesFile, maxImage, dzLabel);
                        })(maxWidth, maxHeight, imagePreview, file);
                    })(file);
                }
            }
        });

        inputFile.on("change", function () {
            dzLabel.hide();

            if (this.files && this.files.length) {
                var maxImage = parseInt(inputFile.attr("data-max")),
                    thumbs = fesFile.find(".dz-preview.has-image");

                if (this.files.length <= maxImage && (!thumbs.length || (thumbs.length + this.files.length) <= maxImage)) {
                    // Do upload file instantly after file chosen.
                    var files = this.files,
                        i = 0,
                        count = files.length,
                        maxSize = parseFloat(inputFile.attr("data-max-size"));

                    //dzLabel.hide();

                    for (i; i < count; i++) {
                        var file = files[i];

                        if (file) {
                            if (file.size > (maxSize * 1024 * 1024)) {
                                inputFile.val(null);
                                inputFile.trigger("change");

                                return;
                            }

                            (function (file) {
                                var imagePreview = fesFile.find("div.dz-preview:not(.has-image):not(.dz-processing)").first();

                                if (!imagePreview.length) {
                                    fesFile.append(pixelify.imagePreview);
                                    imagePreview = fesFile.find("div.dz-preview:not(.has-image):not(.dz-processing)").first();
                                }

                                //imagePreview.addClass("dz-processing");

                                var maxWidth = parseInt(inputFile.attr("data-max-width")),
                                    maxHeight = parseInt(inputFile.attr("data-max-height"));

                                (function (maxWidth, maxHeight, imagePreview, file) {
                                    var img = new Image();

                                    img.src = window.URL.createObjectURL(file);

                                    img.onload = function () {
                                        var width = img.width,
                                            height = img.height;

                                        window.URL.revokeObjectURL(img.src);

                                        if (width > maxHeight || height > maxHeight) {
                                            imagePreview.removeClass("dz-processing");
                                            imagePreview.addClass("dz-error");
                                        }
                                    };

                                    var reader = new FileReader();

                                    reader.onload = function (e) {
                                        imagePreview.find(".dz-image img").attr("src", e.target.result).show();
                                        imagePreview.show();
                                    };

                                    reader.readAsDataURL(file);

                                    hocwp_theme_remove_image_preview(imagePreview, inputFile, fesFile, maxImage, dzLabel);
                                })(maxWidth, maxHeight, imagePreview, file);
                            })(file);
                        }
                    }
                } else {
                    alert("You cannot upload more than 5 images");
                    inputFile.val(null);
                    inputFile.trigger("change");

                    if (this.files.length === 1) {
                        dzLabel.hide();
                    } else {
                        dzLabel.show();
                    }
                }
            }
        });

        body.on("click", ".add-forum form[name='fes-submission-form'] input[type='submit']", function () {
            let that = this,
                element = $(that),
                form = myForm,
                upload = form.find("input[name='product_images']");

            if (upload[0].files.length === 0) {
                form.addClass("upload-done");
            }
        });

        function continueSubmitForm(element) {
            setTimeout(function () {
                element.addClass("upload-done");
                element.unbind("submit").submit();
                element.find("input[type='submit']").click();
            }, 2000);
        }

        $(".add-forum form[name='fes-submission-form']").on("submit", function (e) {
            let that = this,
                element = $(that),
                upload = element.find("input[name='product_images']");

            if (!element.hasClass("upload-done")) {
                e.preventDefault();
            }

            upload.on("uploadCompleted", function () {
                continueSubmitForm(element);
            });

            if (upload[0].files.length) {
                upload.trigger("uploadFile");
            } else {
                continueSubmitForm(element);
            }

            return true;
        });
    })();
});

Thêm một đoạn code mô tả quá trình tải tệp lên máy chủ bằng AJAX. Trong quá trình tải lện sẽ cập nhật trạng thái phần trằm hoàn thành. Sau khi hoàn tất quá trình tải lên, sẽ ẩn thanh trạng thái và hiển thị bản xem thử cho người dùng.

5/5 - (1 bình chọn)

Lại Đình Cường

Tôi làm quen và phát triển WordPress từ năm 2008, cho đến nay thì đã có hơn 13 năm kinh nghiệm, thật không thể tin được. Tôi có đam mê và dành nhiều thời gian làm việc với WordPress mỗi ngày, hiện tại tôi đang phát triển giao diện và plugin cho WordPress.

Nếu bạn đang cần người làm trang web bằng WordPress? Hãy liên hệ với tôi ngay để được tư vấn nhé.