Sticky sidebar not working after you turned on a cache plugin
Last updated: 4 November 2026
Your sticky widget worked until you switched on WP Rocket, LiteSpeed Cache, Perfmatters or another speed plugin, and now it scrolls away with the page, or sticks only after you move the mouse. That is almost always the optimizer holding back the sticky plugin's JavaScript. This page explains the three ways it happens, how to recognise each one, and the exclusions that fix it for the most common sticky plugins.
We make a sticky widget plugin, Quicksloth Sticky Widget, so we are not neutral. We are not affiliated with any of the plugins or services named here. On 4 November 2026 we tested LiteSpeed Cache 7.9.3 and Autoptimize 3.1.17 on a test site with WordPress 7.1.4 and Twenty Twenty-Five, in Chromium 153 and Firefox 155, with our plugin (version 1.0.2) and with Fixed Widget 6.2.3. WP Rocket, Perfmatters, W3 Total Cache, SiteGround Speed Optimizer and Cloudflare Rocket Loader are not tested by us: what we say about them comes from their official documentation or from their plugin's code, with the date we read it. If your sticky sidebar was never working, the causes are in CSS instead: see six reasons a sticky sidebar does not work.
Short version
- If the widget sticks only after the first mouse move, scroll wheel, key or touch, a "delay JavaScript" option is on: Delay JavaScript execution in WP Rocket, Load JS Deferred set to Delayed in LiteSpeed Cache, Delay JavaScript in Perfmatters.
- Exclude both parts of the sticky plugin: its script file and the small inline script with its settings. For Quicksloth Sticky Widget that is two lines,
quicksloth-sticky-widgetandqsswConfig; for Fixed Widget (q2w3) the single wordq2w3covers both. - Excluding only the file is a trap: in our test the widget then stuck at the default 10 px instead of the 60 px set in the plugin, before and after the first interaction.
- After changing widgets or sticky settings, clear the cache: a cached page keeps the old version.
Why a cache plugin stops a sticky sidebar
A sticky widget plugin is a script: it finds the marked widgets, measures the page and keeps them in view as you scroll. Speed plugins change when and how scripts run, in three ways that matter here.
- Scripts wait for an interaction. WP Rocket describes its option as "delaying the loading of all JavaScript files and inline scripts until there is a user interaction" (WP Rocket, last updated 11 March 2026). LiteSpeed Cache's Delayed and Perfmatters' Delay all scripts do the same. Until the visitor moves the mouse over the page, uses the wheel, a key or a touch, the sticky script has not run, and the widget scrolls away like any other box. In our test with LiteSpeed Cache's Delayed, the widget was 2,429 px above the window when we scrolled a third of the way down without touching the page, and stuck at the right place after one turn of the mouse wheel.
- The script and its settings are split up. Most sticky plugins print their settings in a small inline script right before their file (in WordPress, with
wp_add_inline_script()orwp_localize_script()). If you exclude only the file, the file runs at once and the settings arrive later with the delayed scripts. Depending on the plugin it then uses its defaults or fails. Plugins that depend on jQuery can fail the same way when jQuery is delayed or loaded after them. - The page cache serves an old copy. If you mark a new widget as sticky, or change a margin, visitors keep getting the cached page from before the change until the cache is cleared or expires.
These problems are common. In the titles of the last 1,201 threads of the support forum of Fixed Widget (read on 4 November 2026), at least 16 name a cache or optimization plugin: WP Rocket, Autoptimize, W3 Total Cache, Hummingbird, Fast Velocity Minify, WP Super Cache, Cloudflare's Rocket Loader and "jquery in defer mode". Outside that forum, one WordPress.org thread reports a sticky bar that stopped with WP Rocket and came back with the delay turned off.
How to tell which one it is
- Open a long post in a private window, so you see the page as a logged-out visitor does: some optimizers treat logged-in users differently.
- Keep the pointer still, outside the page, while it loads, then watch the widget. If it is not sticky and snaps into place only when you move the mouse over the page, turn the wheel or press a key, it is cause 1: a delay.
- Check in DevTools: right-click the page, choose Inspect, and search the Elements panel (Ctrl+F, or Cmd+F on a Mac) for the sticky plugin's file name. A delayed script has its type changed:
type="rocketlazyloadscript"with WP Rocket,type="litespeed/javascript"with LiteSpeed Cache. With LiteSpeed's JS Combine on, the file is gone from the page and its code is inside a combined file in/wp-content/litespeed/js/. - If the widget sticks without any interaction but at the wrong distance from the top, or ignores your other settings, it is cause 2: the file runs and its settings do not.
- If you changed a widget or a setting recently and visitors still see the old behavior, it is cause 3: clear the cache. Adding a query string such as
?test=1to the address often gets an uncached copy to compare with.
A delay can look random across browsers. In our earlier tests with LiteSpeed Cache, Chromium started delayed scripts by itself when the pointer was over the page as it loaded, because it sends a mouseover event there; Firefox and Safari's engine did not. A sticky widget that "works in Chrome only" after you turned on an optimizer is a strong hint of cause 1.
The exclusions for each sticky plugin
The optimizers compare each line you enter with the address of a script file, and with the text of an inline script. So a good exclusion is a word that appears in the plugin's file path and, if needed, a word that appears only in its inline settings.
| Sticky plugin | Lines to exclude from delay | Script handle (for lists by handle) | Tested by us |
|---|---|---|---|
| Quicksloth Sticky Widget | quicksloth-sticky-widgetqsswConfig | qssw-sticky | Yes, LiteSpeed Cache 7.9.3 |
| Fixed Widget (q2w3) 6.2.3 | q2w3 | q2w3_fixed_widget | Yes, LiteSpeed Cache 7.9.3 |
| Astra or Kadence sticky sidebar option | Usually nothing | - | No |
- Quicksloth Sticky Widget loads
/wp-content/plugins/quicksloth-sticky-widget/assets/sticky.jsand, right before it, an inline script that setswindow.qsswConfig. The first line matches the file, the second the settings. - Fixed Widget 6.2.3, not updated since 30 March 2023, loads
/wp-content/plugins/q2w3-fixed-widget/js/frontend.min.jsand an inlineq2w3_sidebar_optionswith its settings. Both containq2w3, and with that one line the widget behaved as it did without LiteSpeed Cache in our test. If you are thinking of replacing it, see the Fixed Widget alternative page. - Theme options: Astra's and Kadence's Enable Sticky Sidebar mostly work through CSS rules the theme prints (we read their code for our theme guide), so delaying JavaScript should not stop them from sticking. Astra also runs a small script that adjusts the sidebar's height and offset, which waits like any other. We have not tested either theme with a cache plugin.
- Another sticky plugin: find its script in DevTools as above, and use a part of its folder name (for example
/plugins/its-folder-name/) plus a word that appears only in its inline settings, if it has any.
LiteSpeed Cache
The labels below are copied from the code of LiteSpeed Cache 7.9.3, released on 3 November 2026.
- Where the delay is: LiteSpeed Cache → Page Optimization → JS Settings → Load JS Deferred, with three choices: OFF, Deferred and Delayed. Only Delayed waits for an interaction. The Extreme preset under LiteSpeed Cache → Presets (which needs a QUIC.cloud connection) turns Delayed on; the other presets use Deferred or OFF.
- How long it waits: in 7.9.3 the delayed scripts start on the first
mouseover,click,keydown,wheel,touchmove,touchstart,pointeruporpointerdown. There is no timer: until a visitor does one of these, the widget does not stick. - The fix: under LiteSpeed Cache → Page Optimization → Tuning, add the lines from the table to JS Deferred / Delayed Excludes, one per line, save and purge the cache. The box already holds
jquery.js,jquery.min.js,gtm.jsandanalytics.jsby default; keep them.
What we saw with CSS Minify, CSS Combine, JS Minify, JS Combine and JS Combine External and Inline on, and the margin top of our plugin set to 60 px:
| Load JS Deferred | JS Deferred / Delayed Excludes | Before any interaction | After a mouse move and wheel |
|---|---|---|---|
| Deferred | default | Sticky at 60 px | Sticky at 60 px |
| Delayed | default | Not sticky | Sticky at 60 px |
| Delayed | + quicksloth-sticky-widget | Sticky at 10 px, the default | Still at 10 px |
| Delayed | + quicksloth-sticky-widget and qsswConfig | Sticky at 60 px | Sticky at 60 px |
The same results in Chromium 153 and Firefox 155. With Fixed Widget 6.2.3 and Delayed, the widget was not pinned before the first interaction; with q2w3 in the excludes it was pinned from the start, as without LiteSpeed Cache. LiteSpeed's full page cache needs a LiteSpeed web server and was not part of our test; the optimization above runs on any server.
WP Rocket
WP Rocket is a paid plugin and not tested by us. From its documentation (Delay JavaScript execution, last updated 11 March 2026, and Troubleshoot Delay JavaScript execution issues, last updated 19 January 2026, both read on 4 November 2026):
- The option is Delay JavaScript execution, on the File Optimization tab. It "is applied only on cached or optimized pages", and the scripts run on interactions such as mouse moves, touches, scrolling, keys and the wheel.
- Exclusions go in the Excluded JavaScript Files text area or through the One-click exclusions boxes. The documentation says the exclusion "detects keywords, not just filepaths", and that for an inline script you "choose a string of text that is unique to that script". So the two lines from the table should work:
/quicksloth-sticky-widget/(or the plain slug) for the file andqsswConfigfor the settings;q2w3for Fixed Widget. - Safe Mode for Delay JavaScript Execution excludes, among others, everything under
/wp-content/and inline scripts added withwp_add_inline_script(). That covers our plugin too, but WP Rocket calls it "a temporary solution, while you find the specific files that need to be excluded". - The troubleshooting article opens the page with
?nowprocketadded to the address to compare it with the page without WP Rocket's optimizations: if the widget sticks there and not on the normal page, WP Rocket is the cause.
Perfmatters
Perfmatters is a paid plugin and not tested by us. Its delay JavaScript documentation (updated 1 October 2026, read on 4 November 2026) puts the option under the plugin's settings, JavaScript menu, Delay section, Delay JavaScript. It has two behaviors:
- Only delay specified scripts delays only what you list, so a sticky plugin is affected only if you added it.
- Delay all scripts delays everything, inline scripts included. Add the lines from the table to Excluded from delay, one per line; the documentation says an inline script is matched by "a unique string from that script", and that a script with a file and an inline part needs both.
Its optional timeout loads delayed scripts after 15 seconds without interaction; the documentation says it is off by default.
Autoptimize
The free Autoptimize 3.1.17 (released on 25 October 2026) has no option that waits for an interaction: its code offers aggregating and deferring under Settings → Autoptimize → JS, CSS & HTML. All three set-ups we tried kept our widget sticky at the 60 px we had set, before any interaction, in both browsers:
- Autoptimize's defaults for a new install: Optimize JavaScript Code?, Do not aggregate but defer? and Also defer inline JS? on. The settings became a deferred inline script and the file a deferred minified copy, in the original order.
- Aggregate JS-files? on (with Aggregate CSS-files?): the file went into the aggregated file, the settings stayed inline before it.
- Aggregate JS-files? and Also aggregate inline JS? on: both went into the aggregated file, in order.
If another sticky plugin breaks with Autoptimize, add its folder name to Exclude scripts from Autoptimize:, a comma-separated list, and keep the entries that are already there. We have not looked at the options of Autoptimize Pro.
W3 Total Cache and SiteGround Speed Optimizer
Both are not tested by us; the labels come from the code of the versions on WordPress.org on 4 November 2026.
- W3 Total Cache 2.11.0: the free plugin combines and minifies JavaScript under Performance → Minify, where each area of the page has an embed type such as Default (blocking) or Non-blocking using "defer". If the widget breaks after turning that on, add the sticky plugin's file to Never minify the following JS files:. Its Delay Scripts feature is marked as a Pro feature in the code, delays only the scripts on its Delay list:, and has a Timeout: for visitors who do not interact.
- SiteGround Speed Optimizer 7.8.6 (slug
sg-cachepress): its JavaScript options are Minify JavaScript Files, Combine JavaScript Files and Defer Render-blocking JavaScript, with Exclude from JavaScript Combination and Exclude from Deferral of Render-blocking JS. These lists work by script handle:qssw-stickyfor our plugin,q2w3_fixed_widgetfor Fixed Widget. We found no option in its code that waits for an interaction.
Cloudflare Rocket Loader
Rocket Loader is a Cloudflare setting, not a plugin, and not tested by us (it needs a site behind Cloudflare). Cloudflare says it defers "the loading of all of your JavaScript until after rendering" and "handles both inline and external scripts, while maintaining order of execution" (Rocket Loader, last updated 14 August 2026, read on 4 November 2026). It does not wait for an interaction, but there is no exclusion list either. Scripts are skipped only if their tag carries data-cfasync="false", which "must be added before the src attribute" (Ignore JavaScripts, last updated 17 April 2026).
If you need that for our plugin, this snippet adds the attribute to both of its script tags. Put it in a small plugin of your own, or in a code snippets plugin:
add_filter( 'script_loader_tag', function ( $tag, $handle ) {
if ( 'qssw-sticky' === $handle ) {
$tag = str_replace( '<script ', '<script data-cfasync="false" ', $tag );
}
return $tag;
}, 10, 2 );
On our test site with WordPress 7.1.4 the page then had <script data-cfasync="false" id="qssw-sticky-js-before"> and <script data-cfasync="false" id="qssw-sticky-js" src="…/sticky.js?ver=1.0.2">, and the widget still stuck at 60 px without Cloudflare. We could not check what Rocket Loader does with them. For Fixed Widget, use 'q2w3_fixed_widget' as the handle.
With Quicksloth Sticky Widget
What the plugin does, from its code (version 1.0.2):
- It loads one script,
sticky.js(about 5 KB compressed), without jQuery and without a stylesheet, in the footer and only on pages that have a sticky widget or block, or when you have set a custom selector. Its settings come in the inline script just before it. - It reads those settings once, when it starts. That is why the settings must not be delayed when the file is not: in our test the widget then used the defaults (10 px from the top, no custom selectors) and kept them after the delayed scripts had run.
- While Fixed Widget is still active, our script stays off, so the two plugins never move the same widget. Deactivate Fixed Widget after switching, and remove
q2w3from the excludes once it is gone. - With a page cache, clear it after you tick a widget as sticky or change the settings under Appearance → Sticky Widget.
The plugin is free in the WordPress.org Plugin Directory. More on what it does and what it does not do.
Quick check list
| What you see | Likely cause | Fix |
|---|---|---|
| Sticks only after the first mouse move or touch | Delay JavaScript (WP Rocket, LiteSpeed Delayed, Perfmatters) | Exclude the plugin's file and its inline settings |
| Sticks, but ignores your margin or other settings | Only the file is excluded | Also exclude the settings (qsswConfig for our plugin) |
| Works in Chrome, not in Firefox or Safari | A delay that Chrome's load-time mouseover starts | As above |
| A new sticky widget does not stick for visitors | Cached page from before the change | Clear the cache |
| Broke after combining or minifying | Order of combined files (often jQuery plugins) | Exclude the plugin from combining |
Sources
- Plugin code from downloads.wordpress.org, downloaded on 4 November 2026: LiteSpeed Cache 7.9.3 (labels in
src/lang.cls.php,tpl/page_optm/andtpl/presets/, events inassets/js/js_delay.js, defaults indata/const.default.json), Autoptimize 3.1.17 (classes/autoptimizeConfig.php), W3 Total Cache 2.11.0 (inc/options/minify.php,Minify_ConfigLabels.php,UserExperience_DeferScripts_Page_View.php), SiteGround Speed Optimizer 7.8.6 (helpers/react-strings.php), Fixed Widget 6.2.3 (q2w3-fixed-widget.php). - WP Rocket, Delay JavaScript execution (last updated 11 March 2026) and Troubleshoot Delay JavaScript execution issues (last updated 19 January 2026), read on 4 November 2026.
- Perfmatters, How to delay JavaScript until user interaction in WordPress (updated 1 October 2026), read on 4 November 2026.
- Cloudflare, Rocket Loader (last updated 14 August 2026) and Ignore JavaScripts (last updated 17 April 2026), read on 4 November 2026.
- Thread titles of the Fixed Widget support forum, last 1,201 threads, read on 4 November 2026.
Related: why a sticky sidebar does not work in the first place, how to make a widget sticky, sticky sidebar in Astra, GeneratePress, Kadence and OceanWP and what AdSense allows for sticky sidebar ads. Still stuck with your optimizer? Write to support@quicksloth.dev with a link to the page and the name of the plugin.
Documentation and plugin code read on 4 November 2026; LiteSpeed Cache and Autoptimize tested the same day as described at the top. Written with AI tools and checked by Quicksloth.