Skip to content
  • FG-47
  • 14 min read
  • Last checked November 7, 2026

How to Fix Menus, Sliders, Popups or Forms That Stopped Working After Turning On Delay JS, Defer or Combine

Your speed plugin reordered or delayed JavaScript and now menus, sliders, popups or forms are dead. Find the failing script and exclude it properly.

Run the health check

You switched on “Delay JavaScript execution”, “Load JavaScript deferred”, “Combine JavaScript files” or “Minify JavaScript” and your speed score went up. Then someone told you the mobile menu does not open, the hero slider is a stack of images, the cookie banner never appears, or the contact form submits to nowhere. In the browser Console you may see Uncaught ReferenceError: jQuery is not defined, Uncaught TypeError: $ is not a function or Uncaught ReferenceError: SOMETHING is not defined.

Nothing is wrong with your theme or your builder. The optimization changed when and in what order your scripts run, and one script now runs before the thing it depends on exists, or does not run until someone moves the mouse. This guide is for site owners, designers and freelancers who use WP Rocket, LiteSpeed Cache, Autoptimize, Perfmatters, FlyingPress, SiteGround Optimizer or a similar tool. If your whole layout is unstyled instead, that is a CSS problem and is covered in the CSS not loading guide.

What is happening

A browser reads your HTML from top to bottom. A normal <script src="..."> tag stops the parser, downloads the file, runs it, and only then continues. WordPress relies on that order: it prints jQuery first, then jQuery Migrate, then every plugin file that declared jQuery as a dependency, and it prints small inline scripts (configuration objects, translations, nonces) right before or after the file that needs them.

Speed plugins change that model in four different ways. Each breaks things in its own way.

Optimization What it does Typical breakage
Defer Adds the defer attribute so files download in parallel and run after the HTML is parsed, in document order. Inline scripts that call jQuery(...) run immediately, but jQuery itself is now deferred, so you get “jQuery is not defined”.
Delay until interaction Rewrites script tags so they do not run at all until the visitor scrolls, moves the mouse, taps or presses a key (or a timeout fires, if the plugin has one). Anything that must work on first paint is dead: sliders, above the fold animations, the menu toggle, cookie banners, chat widgets, lazy loaded hero images.
Combine Concatenates many files into one or a few bundles. One syntax error or a file that expects to be global breaks the whole bundle. Order inside the bundle may differ from the original order.
Minify Strips whitespace and comments, sometimes rewrites code. A file that relies on automatic semicolon insertion, or that was already minified, can be mangled into a syntax error.

The key idea is dependency. A script that calls jQuery, $, wp.i18n, Swiper or elementorFrontendConfig needs that name to exist at the moment it runs. If it runs too early, it throws a ReferenceError and stops. Every later line in that script is skipped, which is why one error can kill a menu, a slider and a form at once.

About “$ is not a function”: WordPress loads jQuery in noConflict mode, so the global $ is not set to jQuery. Code written as jQuery(function($){ ... }) is fine. Code that uses bare $ at the top level only worked before because some other script happened to define it. Reordering exposes that hidden bug.

Before you start

  • Access you need: a WordPress admin login with access to the speed plugin settings. SSH is helpful but not required for this problem.
  • Backup: export your speed plugin settings before you change anything. WP Rocket has Tools, then Export settings. LiteSpeed Cache has Toolbox, then Import / Export. Autoptimize settings live in normal WordPress options and are backed up with the database.
  • Browser: use Chrome, Edge or Firefox on a desktop. DevTools opens with F12, or Cmd+Option+I on a Mac.
  • Logged out testing: most speed plugins do not optimize pages for logged in administrators, so the bug may be invisible to you. Test in a private window where you are not logged in.
  • How to run commands: the few commands below run in your own computer’s terminal (macOS and Linux have curl built in; on Windows use WSL, or curl.exe in PowerShell). Server commands run over SSH in the site folder, the one that contains wp-config.php, using wp or wp-cli depending on how your host installed WP-CLI.

Step 1: Prove the speed plugin is the cause

Use a verified bypass parameter

Several plugins have a URL parameter that serves the page without their optimizations. Only use parameters the plugin documents:

Plugin Bypass Notes
WP Rocket ?nowprocket Skips WP Rocket caching and its file, media and CDN optimizations. A host or Cloudflare cache may still serve a cached copy depending on how it treats query strings.
LiteSpeed Cache ?LSCWP_CTRL=before_optm Shows the page before page optimization is applied.
Autoptimize ?ao_noptimize=1 Disables Autoptimize for that request.

For any other plugin, do not guess a parameter; turn off its JavaScript options and purge instead.

Open the broken page in a private window, then open https://example.com/PAGE_PATH/?nowprocket (or the matching parameter). If the menu or form works on the bypass URL and fails on the normal URL, you have confirmed the cause. If it fails on both, the problem is not the optimization; check FG-07 for builder update problems instead.

Confirm which optimization it is

In the plugin settings, switch off JavaScript options in this order and purge all caches after each change: Delay JavaScript, then Defer, then Combine, then Minify. The first switch that fixes the page tells you which mechanism you are dealing with, and the rest of this guide tells you how to keep that optimization on while excluding only what needs excluding.

Step 2: Find the failing script in the Console

Read the first error, not the last

Open DevTools, select the Console tab, check “Preserve log” so errors survive a reload, then reload the page. Red errors appear in the order they happened. The first one is usually the cause and the rest are knock on effects.

Uncaught ReferenceError: jQuery is not defined
    at example.com/:412:5
Uncaught TypeError: Cannot read properties of undefined (reading 'init')
    at frontend.min.js?ver=VERSION:2:10871

This is example Console output. The first line says inline code on line 412 of the page itself (the example.com/ location) called jQuery before jQuery existed. VERSION stands for whatever version string your file carries. The second error is a consequence: a builder script expected an object that the first, failed script should have created. Fix the first and the second usually disappears.

Click through to the Sources panel

Click the blue file and line link on the right of the error. DevTools jumps to the Sources panel with the line highlighted. If the file is a combined or minified bundle, click the {} “Pretty print” button at the bottom of the editor to make it readable. Look at the surrounding code for a recognizable name, such as a plugin slug in a comment, a variable like wpcf7 (Contact Form 7), elementorFrontend or gform (Gravity Forms). That tells you which plugin owns the code.

Find the script tag in the delivered HTML

In the Elements panel press Ctrl+F (Cmd+F on a Mac) and search for the plugin slug. When a script is delayed, the tag looks different from normal. WP Rocket, for example, changes delayed tags to type="rocketlazyloadscript" and moves src into a data-rocket-src attribute. Other plugins use their own type values. If the script you need on first paint has one of these rewritten types, it is being delayed and needs an exclusion.

Check the Network panel for missing files

Open the Network tab, filter by JS, and reload. A combined file returning 404 (usually because a cache was purged without regenerating the minified files, or because a CDN cached an old HTML page pointing to a deleted bundle) produces errors that look like dependency bugs. Clear the plugin cache and the CDN cache together, then reload.

Step 3: Fix “jQuery is not defined” and “$ is not a function”

Confirm the pattern

View the page source (Ctrl+U) and search for jquery.min.js. Note whether it has defer, a delayed type, or has been folded into a combined file. Then search for the inline script on the line number from the Console. If that inline block calls jQuery and appears above the point where jQuery actually runs, you have found the dependency break.

Fix it in the plugin

  • Delay JS: exclude jQuery and jQuery Migrate from delay. WP Rocket already keeps them in its built in compatibility exclusions in recent versions, but a custom entry or an old version may override that. Add /jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js and jquery-migrate(.min)?.js to the exclusion box (WP Rocket accepts partial paths and regular expression style patterns in that field).
  • Defer: most plugins have an “exclude from defer” field. Add /wp-includes/js/jquery/jquery.min.js there. On WP Rocket, excluding jQuery from Load JavaScript Deferred also causes inline scripts to be left alone, which is usually exactly what you want.
  • Combine: exclude jQuery from combining, or turn combining off. Over HTTP/2 and HTTP/3, combining gives little benefit and causes most of these breakages.

The $ problem in your own code

If the failing code is yours (a snippet in a code snippets plugin, a builder custom code area or a child theme), wrap it so it does not rely on a global $:

jQuery(function ($) {
  // your existing code that uses $ goes here
});

This goes in the file or snippet box that contains your custom JavaScript. It has no placeholders. jQuery(function ($) { ... }) waits for the DOM to be ready and passes jQuery in as $ for the code inside. Good result: the “$ is not a function” error disappears from the Console. Bad result: you now see “jQuery is not defined” instead, which means jQuery itself is still delayed or deferred after your snippet; go back to the previous section.

Step 4: Fix scripts that must run before the first interaction

Delay until interaction is the most aggressive optimization and the most common cause of “the slider is just a pile of images” and “the menu does nothing on mobile”. It is also the most valuable for scores, so the goal is to exclude only what is visible and interactive on first view.

How to confirm

Load the page in a private window and do not touch anything for ten seconds. If the slider starts or the menu begins working the moment you move the mouse or scroll, delay is the cause. On phones the first tap is often consumed as the “interaction” that wakes the scripts, so the first tap on the menu button does nothing and the second works. That pattern is a clear signature.

What usually needs excluding

Feature Exclusion pattern to try
jQuery and Migrate /jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js and jquery-migrate(.min)?.js
Elementor frontend (menus, sliders, popups) /elementor/assets/js/, /elementor-pro/assets/js/, elementorFrontendConfig, ElementorProFrontendConfig
Swiper based sliders swiper
Slider Revolution /revslider/, setREVStartSize, revapi
Theme navigation script /themes/THEME_SLUG/, or the exact file such as /themes/THEME_SLUG/js/navigation.js
Cookie consent banner The plugin folder, for example /plugins/PLUGIN_SLUG/, plus its inline config variable name

Replace THEME_SLUG with your theme’s folder name (shown in the file path in the Sources panel, or under wp-content/themes/) and PLUGIN_SLUG with the plugin’s folder name under wp-content/plugins/. The patterns are matched against the script URL or the inline script content, so a variable name such as elementorFrontendConfig catches the inline configuration block that the external file needs.

Before typing patterns by hand, check whether your plugin offers a ready made list. WP Rocket 3.13 and later has “One-click exclusions” under the Delay JavaScript setting, with checkboxes for common plugins, themes and services. WP Rocket also has a “Safe Mode” for Delay JavaScript that excludes jQuery, Migrate and most scripts under /wp-content/ and /wp-includes/. Treat it as a diagnostic: turn it on, confirm the page works, then turn it off and add narrow exclusions instead.

Why excluding one file is often not enough

Dependencies form a chain. If you exclude slider.min.js from delay but jQuery is still delayed, the slider throws “jQuery is not defined” earlier than before. When you exclude a script, also exclude everything it depends on: jQuery, any library it uses, and its inline configuration block. The Console will tell you what is missing; keep adding the next missing name until the page is clean.

Step 5: Handle inline scripts that depend on deferred files

WordPress attaches inline code to registered scripts with wp_add_inline_script() and wp_localize_script(). In the page source these appear with ids ending in -js-before, -js-after or -js-extra, for example <script id="contact-form-7-js-extra">. The -js-extra and -js-before blocks usually define configuration objects the file needs; -js-after blocks usually call into the file.

Problems appear when the plugin defers the external file but leaves the inline -js-after block running immediately. It calls a function that does not exist yet. The fixes, in order of preference:

  1. Exclude the external file from defer or delay, so it runs before its -js-after block.
  2. Use the plugin’s option to also defer or delay inline scripts, so they keep their relative order. LiteSpeed Cache has separate fields for this; WP Rocket handles inline scripts as part of Delay JavaScript.
  3. Exclude the inline block by a unique string inside it (a function or variable name), so both stay in place.

Forms are a frequent victim here because their nonce or REST URL lives in an inline -js-extra block. If the form “submits” but the page simply reloads, or the spinner never stops, check the Console for an undefined configuration object such as wpcf7.

Step 6: Check jQuery Migrate and old code

jQuery Migrate restores deprecated jQuery functions for older plugins. Some speed plugins and themes offer “Remove jQuery Migrate”. If an old slider or lightbox then calls a removed method, you see errors such as jQuery(...).live is not a function. Search the page source for jquery-migrate; if it is missing and you see these errors, re-enable Migrate, then update or replace the plugin named in the stack trace.

Step 7: Fix combine and minify failures

Confirm

A minify or combine break shows as Uncaught SyntaxError: Unexpected token or missing ) after argument list pointing into a cached file under a path such as /wp-content/cache/min/ or /wp-content/litespeed/js/. A SyntaxError means the browser could not parse the file at all, so nothing in it ran.

Fix

Pretty print the bundle in Sources, identify the original file around the error, and exclude it from minify or combine. If you cannot tell, turn combine off. Purge afterward, because old bundles stay on disk and in CDN caches.

Step 8: Test systematically

Random toggling wastes hours. After every change: purge the plugin, server and CDN caches; open a fresh private window; wait five seconds without touching anything; then open the mobile menu, every slider, tab set and popup, submit each form with test data, and walk through cart and checkout if you have a shop. Check the Console for red errors on each page, and repeat on a real phone.

Enable one optimization, run the script, fix what broke with narrow exclusions, then enable the next.

Advanced: Tracing execution order with DevTools

When the Console does not make the order obvious, watch execution directly.

Event listener breakpoints

In Sources, open the right sidebar, expand “Event Listener Breakpoints”, then “Script”, and check “Script First Statement”. Reload. DevTools pauses at the first line of every script as it starts, in the real order the browser runs them. Press F8 to continue to the next one. Watch where jQuery runs relative to the script that fails. This is the fastest way to see what a combine or delay setting really did.

Checking a name at a moment in time

At any pause, type a name into the Console, such as typeof jQuery. A result of "undefined" at the point where the failing script starts proves the dependency is not loaded yet. "function" means it is present and you should look elsewhere.

Comparing the optimized and bypass HTML

curl -s "https://example.com/PAGE_PATH/" > optimized.html
curl -s "https://example.com/PAGE_PATH/?nowprocket" > original.html
diff <(grep -o '<script[^>]*' original.html) <(grep -o '<script[^>]*' optimized.html)

Run this on your own computer in bash or zsh (the <( ) syntax does not work in PowerShell; use WSL). Replace the URL and use your plugin’s documented bypass parameter. The first two lines save both versions of the page; the third compares only their script tags. Lines starting with < exist only in the original, and lines starting with > exist only in the optimized page. A good diff shows only attribute changes on scripts you are happy to delay. A bad diff shows your menu, slider or form script turned into a delayed type, or missing entirely because it was folded into a bundle.

Third party embeds

Delaying chat widgets is usually fine, but reCAPTCHA and payment scripts on form and checkout pages should be excluded so the form is ready on arrival. Exclude by domain, for example recaptcha or js.stripe.com.

When to contact your host

Open a ticket when a server layer looks involved:

  • The bypass parameter still shows the broken version, which suggests a server or CDN cache ignoring query strings.
  • Combined files return 403 or 404 even after a purge, which can mean a permissions or security rule problem.
  • Your host runs its own optimization layer (for example a server level minifier or the host’s own caching plugin) in addition to yours.

Send the exact page URL, the UTC time you tested, the first Console error copied as text, the response headers of the page from the Network tab, the list of optimizations you have on, and which bypass URL you tried. Mention what changed and when. If the site is fully down, go to the Emergency Room; the diagnostic tools help you collect headers.

Still stuck?

Print a free one-page checklist to keep, or open the Emergency Room if the symptom does not match.

Get the free checklists

Keep reading

All field guides
FG-130 Performance

How to Fix Cumulative Layout Shift (CLS) on WordPress

Content jumps as the page loads and Search Console reports a CLS issue. Find the element that moves and why, then reserve space for images, embeds, ads, fonts and banners.

Read the guide
10 min read

Search the field manual

What is going wrong?

Press / to search from any page, Esc to close