WPBakery Bug in Change Handler

February 17th, 2020 UpdateAlthough no specific entry was added in the WP Bakery changelog, it has been reported that this bug is now fixed in the current WPBakery version 6.1.0 release.

The WPBakery (aka Visual Composer) changeHandler function uses the “vc.accordion” data attribute without first checking for it’s existence. Any plugin or theme using a jQuery show / hide event trigger will trip this bug, and the post editing page will fail to load properly.

I’ve posted a bug report to the Visual Composer channel on Slack, but the channel does not seem to be read by WPBakery employees, so this bug may continue to go unfixed. If you are a WPBakery customer affected by this issue, you may want to report the bug to WPBakery.

The unminified WPBakery code looks like this – notice that the data("vc.accordion") attribute is being used here without first checking if the attribute actually exists or not.

changeHandler = function(e) {
    var caller;
    void 0 === (caller = $(e.target).data("vc.accordion")).getRelatedTab && (caller.getRelatedTab = function() {
        var findTargets;
        return findTargets = function() {
            return caller.getContainer().find("[data-vc-tabs]").filter(function() {
                var $this;
                return void 0 === ($this = $(this)).data("vc.accordion") && $this.vcAccordion(), $this.data("vc.accordion").getSelector() === caller.getSelector()
            })
        }, caller.isCacheUsed() ? (void 0 === caller.relatedTab && (caller.relatedTab = findTargets()), caller.relatedTab) : findTargets()
    }), Plugin.call(caller.getRelatedTab(), e.type)
}

There are many examples of jQuery code to trigger a show / hide event – here are two popular jQuery examples that will trip the WPBakery change handler bug. Other types of jQuery event handlers (click, hover, etc.) may also trip this bug, but I’ve only tested the jQuery show / hide events.

(function ($) {
    $.each(['show', 'hide'], function (i, ev) {
        var el = $.fn[ev];
        $.fn[ev] = function () {
            this.trigger(ev);
            return el.apply(this, arguments);
        };
    });
})(jQuery);
(function ($) {
    $.each(['show', 'hide', 'fadeOut', 'fadeIn'], function (i, ev) {
        var el = $.fn[ev];
        $.fn[ev] = function () {
            var result = el.apply(this, arguments);
            result.promise().done(function () {
                this.trigger(ev, [result]);
            });
            return result;
        };
    });
})(jQuery);
Find this content useful? Share it with your friends!