=== Quicksloth Sticky Widget – Fixed Widgets, Blocks & Sticky Sidebar ===
Contributors: quicksloth
Tags: sticky widget, sticky sidebar, sticky block, fixed sidebar, sidebar
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Sticky widgets, blocks and sidebar elements that stay in view and stop before the footer. Keeps your existing Fixed Widget settings. No jQuery.

== Description ==

Keep a sidebar widget, a block or any element of your theme in view while visitors scroll down a long page, and stop it before the footer instead of covering it. Works with classic widgets, with any block (WordPress's own Sticky setting covers only Group blocks, on themes that turn it on) and with any element you point to with a CSS selector.

= How to make something sticky =

* **Classic widget:** under **Appearance → Widgets**, open the widget and tick **Sticky (stays in view while scrolling)**.
* **Block:** select it and turn on **Sticky** in the Sticky panel of the block settings, in the post, site and block widgets editors. **Stop here** marks a block that sticky blocks must not cover.
* **Block theme** (no **Appearance → Widgets**): under **Appearance → Editor**, select a block in a template or template part and turn on **Sticky**.
* **Any other element:** list its ID, class or tag under **Custom sticky elements** on the settings page, one per line.

= Settings =

One page under **Appearance → Sticky Widget** (also from the **Settings** link on the Plugins screen):

* **Margin top** (10 px by default) and **Margin bottom** (0): distance from the window edges and from stop elements.
* **Stop elements:** selectors of elements that push the sticky element up, one per line. **Also stop before the theme footer (footer, #colophon, .site-footer)** is on by default.
* **Custom sticky elements:** selectors of other elements that should stay in view.
* **Minimum screen width** and **Minimum screen height:** below these window sizes nothing is sticky (0 = no limit).
* **Devices:** Desktop, Tablet, Phone. Phone is a window under 768 px, tablet 768 to 1024 px, desktop above.
* **Layer (z-index)**, 50 by default: raise it if a sticky element hides behind the content, lower it if it covers a fixed header.

= Coming from Fixed Widget =

On activation the plugin imports your Fixed Widget (q2w3) settings automatically: margins, stop elements, custom elements (bare IDs of version 5 included) and minimum width and height. Widgets ticked as fixed there, and blocks with its `FixedWidget__fixed_widget` and `FixedWidget__stop_widget` classes, stay sticky without a click. Its settings are never changed or deleted, so you can switch back. While it is still active this plugin keeps its script off (two scripts would make the same widgets jump) and the settings page says so; deactivate it and everything starts by itself.

= How it is built =

* `position: sticky` where the column allows it; otherwise a fixed-position fallback with a placeholder that recalculates the width on zoom, resize and rotation.
* Several sticky elements in one column stack 10 px apart. An element taller than the window is left alone: pinned, it would hide its own end.
* One script of about 5 KB compressed, loaded only on pages that have a sticky element. No jQuery, no extra CSS, no external requests, no cookies.
* No top-level menu and no dashboard notices, except one review request after 14 days, gone for good once you answer it.

= Tested with =

Twenty Twenty-Five, Twenty Twenty-One, Astra, GeneratePress, Kadence and OceanWP; Chromium, Firefox and WebKit (the engine of Safari); zoom from 50 to 200%; window widths from 1280 to 800 px; LiteSpeed Cache 7.9.2 with JavaScript and CSS combined and deferred.

= What this plugin does not do =

Sticky headers and menus, notification bars and popups: other plugins do that.

== Installation ==

1. In your dashboard go to **Plugins → Add Plugin** and search for "Quicksloth Sticky Widget".
2. Click **Install Now**, then **Activate**.
3. Under **Appearance → Widgets**, tick **Sticky (stays in view while scrolling)** in a widget's form, or turn on **Sticky** in the Sticky panel of a block.
4. Optional: margins, stop elements and devices under **Appearance → Sticky Widget**. With a caching plugin, clear its cache after saving.

To install by hand, upload the plugin folder to `/wp-content/plugins/` and activate it under **Plugins**.

== Frequently Asked Questions ==

= I use Fixed Widget. What happens when I switch? =

Activate this plugin before you delete Fixed Widget: deleting it removes its settings, which this plugin imports on activation (the widgets and blocks you marked stay sticky either way). Then deactivate it on the Plugins page; until then this plugin moves nothing. Not imported: "logged_in_req" (sticky only for logged-in users) and "Improved version" (`position: sticky` is always tried first). The stop at the theme footer starts off, as before. While pinned, elements also get the `FixedWidget__fixed_widget__pinned` class, so your CSS keeps working. This plugin is not affiliated with Fixed Widget or its authors.

= My theme is a block theme. Where is Appearance → Widgets? =

Most block themes have no widget areas. Under **Appearance → Editor**, open the template or template part that holds your sidebar, select the block to keep in view (for example a Group block inside a column) and turn on **Sticky** in its Sticky panel.

= Why is my widget not sticky? =

Check these:

* It is taller than the window (pinned, it would hide its own end): make it shorter or split it in two.
* The window is below **Minimum screen width** or **Minimum screen height**, or its device (Desktop, Tablet, Phone) is unticked under **Appearance → Sticky Widget**.
* Fixed Widget is still active: deactivate it on the Plugins page.
* A caching plugin serves an old copy of the page: clear its cache after saving a widget or the settings.

= Does it work with caching and optimization plugins? =

Yes; clear the cache after changing widgets or settings. We tested LiteSpeed Cache 7.9.2 with JavaScript and CSS minified and combined and **Load JS Deferred** set to Deferred: sticky elements work as without it.

With **Load JS Deferred** set to Delayed, scripts run only after the first interaction, so nothing is sticky until the visitor moves the mouse over the page, uses the wheel, a key or a touch. If a widget must be sticky before that, add `quicksloth-sticky-widget` to **JS Deferred / Delayed Excludes** (tested: the slug is enough). Other plugins with a similar "delay JavaScript" feature behave the same way; we have tested this only with LiteSpeed Cache.

= Will it slow down my site? =

It adds one script of about 5 KB compressed, no CSS and no other request, only on pages with a sticky element. In our Lighthouse test on mobile the score was the same with and without the plugin, 99 on Twenty Twenty-Five and 98 on Astra, with Total Blocking Time 3 to 6 ms higher.

= The sticky widget hides behind the content or covers my header. =

Under **Appearance → Sticky Widget** raise **Layer (z-index)** (50 by default) when the element goes behind the content, lower it when it covers a fixed header; with a fixed header also set **Margin top** to its height.

= Is it available in my language? =

The plugin is ready for translation (`.pot` file in `languages/`). Translations into Italian, German, Spanish, French, Portuguese (Brazil) and Dutch were drafted with AI (Claude) and submitted to translate.wordpress.org, where volunteer editors review them before they reach your site. Until a language is approved there, the texts are shown in English.

= Can developers refresh the positions after loading content? =

After adding content with JavaScript (infinite scroll, tabs), call `window.qssw.refresh()` to find and measure the sticky elements again. Classes: `qssw-sticky` on an element to keep in view, `qssw-stop` on an element it must not cover, `qssw-is-pinned` while it is pinned.

== Privacy ==

This plugin does not collect, send or share any personal data. No cookies, no tracking, no telemetry and no requests to external servers, on your site or in your dashboard.

On your server it stores its settings (one option), the date of the first activation and your answer to the review request, plus the Sticky tick in your widgets and the `qssw` attribute in your blocks. Deleting the plugin removes the options and the tick from the widgets in use; it never touches the data of Fixed Widget. The attribute stays in the block content and does nothing without the plugin.

== Screenshots ==

1. A sidebar widget stays in view while the visitor scrolls (GeneratePress).
2. Near the end of the page the sticky widget stops before the footer instead of covering it.
3. The Sticky panel in the block settings, with the Sticky and Stop here switches (Appearance → Widgets).
4. The settings page under Appearance → Sticky Widget, after the automatic import of existing settings.
5. A sticky block inside a column on a block theme (Twenty Twenty-Five).

== Changelog ==

= 1.0.1 =
* The review request no longer has an X that hid it only until the next page: "Write a review" or "Dismiss" closes it for good.
* Readme: the translations are now waiting for review on translate.wordpress.org.

Older versions: [changelog.txt](https://plugins.trac.wordpress.org/browser/quicksloth-sticky-widget/trunk/changelog.txt).

== Upgrade Notice ==

= 1.0.1 =
The review request closes for good with its own buttons. No changes to sticky elements or settings.
