{"id":320255,"date":"2026-07-02T20:05:29","date_gmt":"2026-07-02T20:05:29","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/yieldific-interaction-to-next-paint-inp-hyper-optimizer\/"},"modified":"2026-07-21T06:14:41","modified_gmt":"2026-07-21T06:14:41","slug":"queueforge-inp-fixer","status":"publish","type":"plugin","link":"https:\/\/rhg.wordpress.org\/plugins\/queueforge-inp-fixer\/","author":23298972,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.0","stable_tag":"1.1.0","tested":"7.0.2","requires":"5.0","requires_php":"7.4","requires_plugins":null,"header_name":"QueueForge \u2013 Interaction to Next Paint Fixer","header_author":"Gunjan Jaswal","header_description":"Lowers Interaction to Next Paint (INP) by delaying heavy third-party \/ theme JavaScript until the first real user interaction and yielding the main thread between each script so the browser stays responsive. Includes a live INP + long-task debug overlay.","assets_banners_color":"195083","last_updated":"2026-07-21 06:14:41","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/ko-fi.com\/gunjanjaswal","header_plugin_uri":"https:\/\/github.com\/gunjanjaswal\/Queueforge-INP-Fixer","header_author_uri":"https:\/\/www.gunjanjaswal.me","rating":0,"author_block_rating":0,"active_installs":0,"downloads":106,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"gunjanjaswal","date":"2026-07-02 20:05:05"},"1.1.0":{"tag":"1.1.0","author":"gunjanjaswal","date":"2026-07-21 06:14:41"}},"upgrade_notice":{"1.1.0":"<p>Script delay never actually worked in 1.0.0: delayed scripts were never restored, so the optimisation did nothing. Now fixed. As the behaviour is effectively new, delay arrives switched OFF after this update. Enable it in Settings when ready to check your front end.<\/p>","1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3594468,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3594470,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500-es.png":{"filename":"banner-1544x500-es.png","revision":3594464,"resolution":"1544x500","location":"assets","locale":"es","width":1544,"height":500},"banner-1544x500-es_ES.png":{"filename":"banner-1544x500-es_ES.png","revision":3594465,"resolution":"1544x500","location":"assets","locale":"es_ES","width":1544,"height":500},"banner-1544x500-rtl.png":{"filename":"banner-1544x500-rtl.png","revision":3594466,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3594462,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250-es.png":{"filename":"banner-772x250-es.png","revision":3594459,"resolution":"772x250","location":"assets","locale":"es","width":772,"height":250},"banner-772x250-es_ES.png":{"filename":"banner-772x250-es_ES.png","revision":3594460,"resolution":"772x250","location":"assets","locale":"es_ES","width":772,"height":250},"banner-772x250-rtl.png":{"filename":"banner-772x250-rtl.png","revision":3594461,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3594458,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.1.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[187460,258275,229,247,187459],"plugin_category":[54,59],"plugin_contributors":[245263],"plugin_business_model":[],"class_list":["post-320255","plugin","type-plugin","status-publish","hentry","plugin_tags-core-web-vitals","plugin_tags-inp","plugin_tags-javascript","plugin_tags-performance","plugin_tags-web-vitals","plugin_category-security-and-spam-protection","plugin_category-utilities-and-tools","plugin_contributors-gunjanjaswal","plugin_committers-gunjanjaswal"],"banners":{"banner":"https:\/\/ps.w.org\/queueforge-inp-fixer\/assets\/banner-772x250.png?rev=3594458","banner_2x":"https:\/\/ps.w.org\/queueforge-inp-fixer\/assets\/banner-1544x500.png?rev=3594462","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/queueforge-inp-fixer\/assets\/icon-128x128.png?rev=3594468","icon_2x":"https:\/\/ps.w.org\/queueforge-inp-fixer\/assets\/icon-256x256.png?rev=3594470","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Google's Core Web Vitals now use <strong>Interaction to Next Paint (INP)<\/strong> instead of First Input Delay. Caching plugins make pages <em>load<\/em> fast, but they do nothing about the bloated JavaScript from other plugins, themes, ads, and analytics that blocks the browser's main thread and makes mobile interactions feel choppy.<\/p>\n\n<p>QueueForge INP Fixer attacks INP directly:<\/p>\n\n<ul>\n<li><strong>Delays eligible JavaScript<\/strong> until the visitor's first scroll, tap, key press, or mouse move. The main thread stays free during the critical early window, so the page responds immediately.<\/li>\n<li><strong>Yields the main thread between scripts<\/strong> when the deferred code finally runs, using the native <code>scheduler.yield()<\/code> (with a <code>setTimeout<\/code> fallback) so the queued scripts do not re-block the thread in one long task.<\/li>\n<li><strong>Fallback timeout<\/strong> loads delayed scripts automatically after N seconds even with no interaction, protecting analytics and ad impressions.<\/li>\n<li><strong>Live INP overlay<\/strong> for admins shows measured INP and long-task blocking time right on the front end, using <code>PerformanceObserver<\/code> (<code>event<\/code> + <code>longtask<\/code>).<\/li>\n<\/ul>\n\n<h4>Key Features<\/h4>\n\n<ul>\n<li>Delay all eligible third-party \/ theme JavaScript until first interaction<\/li>\n<li>Main-thread yielding between deferred scripts (<code>scheduler.yield()<\/code> + fallback)<\/li>\n<li>Configurable fallback timeout (0 = interaction only)<\/li>\n<li>Optional jQuery delay (off by default for safety)<\/li>\n<li>Keyword exclusion list, plus per-tag <code>data-no-optimize<\/code> opt-out<\/li>\n<li>Skips logged-in editors so page builders keep working<\/li>\n<li>Live INP + blocking-time debug overlay (admins only)<\/li>\n<li><code>?queueforge_off<\/code> URL switch to bypass the delay for one page load<\/li>\n<li>No database writes on the front end; nothing is cached or stored per visitor<\/li>\n<\/ul>\n\n<h4>Why INP?<\/h4>\n\n<p>INP measures how quickly the page visually responds to <em>every<\/em> interaction across the whole visit, not just the first one. The single biggest cause of poor INP is JavaScript executing long tasks on the main thread while the user is trying to interact. Delaying that JavaScript until it is actually needed \u2014 and breaking its execution into yield-separated chunks \u2014 is the most direct fix.<\/p>\n\n<h4>Developer-Friendly<\/h4>\n\n<ul>\n<li><code>qfinp_exclusions<\/code> filter to programmatically add never-delay keywords.<\/li>\n<li>Uses an output buffer on <code>template_redirect<\/code>; no edits to your theme or other plugins.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>queueforge-inp-fixer<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin through the 'Plugins' menu in WordPress.<\/li>\n<li>Visit <strong>Settings \u2192 QueueForge INP<\/strong> to tune the delay, exclusions, and debug overlay. Defaults work out of the box.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"will%20this%20break%20my%20site%3F\"><h3>Will this break my site?<\/h3><\/dt>\n<dd><p>Delaying JavaScript can affect scripts that expect to run before interaction (consent banners, some sliders, reCAPTCHA). Add a keyword for those scripts to the exclusion list, or add <code>data-no-optimize<\/code> to the tag. Logged-in editors are skipped by default so you can preview safely.<\/p><\/dd>\n<dt id=\"does%20it%20delay%20jquery%3F\"><h3>Does it delay jQuery?<\/h3><\/dt>\n<dd><p>No, unless you enable \"Delay jQuery\". Many themes assume jQuery is present at load, so it is opt-in.<\/p><\/dd>\n<dt id=\"how%20do%20i%20test%20the%20effect%3F\"><h3>How do I test the effect?<\/h3><\/dt>\n<dd><p>Enable the <strong>Live INP overlay<\/strong> in settings and browse the front end while logged in as an admin. Compare against a page loaded with <code>?queueforge_off<\/code> appended to the URL.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20caching%20plugins%3F\"><h3>Does it work with caching plugins?<\/h3><\/dt>\n<dd><p>Yes. It rewrites the HTML as it is generated; the result can be cached normally. It complements page caching rather than replacing it.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.0<\/h4>\n\n<ul>\n<li><strong>Fix: delayed scripts never actually ran.<\/strong> The plugin parked its own configuration object alongside everything else, because WordPress names that tag after the script handle (<code>qfinp-runtime-js-before<\/code>) and the exclusion list only looked for <code>queueforge<\/code>. The runtime booted with an empty config, bound no interaction listeners, set no fallback timer, and restored nothing \u2014 so on every site running 1.0.0, delayed scripts stayed dead for the life of the page. The default \"skip logged-in editors\" setting is why this went unnoticed: signed in, you never saw the optimised page.<\/li>\n<li><strong>Fix: a large inline script could blank the whole page.<\/strong> Past PCRE&#039;s backtrack limit the rewrite returned null, and returning null from an output-buffer handler makes PHP emit an empty response. Roughly 1 MB of inline JavaScript was enough, which page builders produce routinely. The original HTML is now returned untouched instead.<\/li>\n<li><strong>Change: delay is switched off on upgrade.<\/strong> Because the optimisation never ran in 1.0.0, no existing site has ever experienced it. Enabling it automatically would have been shipping brand-new behaviour to every install at once, so upgrades now start with it off and an admin notice explaining why. Fresh installs are unaffected.<\/li>\n<li><strong>Fix: the debug overlay could show to visitors.<\/strong> Config was passed through <code>wp_localize_script<\/code>, which casts every value to a string \u2014 so <code>0<\/code> arrived as <code>\"0\"<\/code>, which is truthy in JavaScript. Now sent as real JSON via <code>wp_add_inline_script<\/code>.<\/li>\n<li><strong>New: re-firing DOMContentLoaded\/load is now opt-in and off by default.<\/strong> Those are global events, so re-dispatching them also re-runs handlers from scripts that were never delayed, double-counting analytics and initialising sliders twice. The namespaced <code>queueforge-scripts-loaded<\/code> event is always emitted.<\/li>\n<li><strong>Fix: scripts marked <code>async<\/code> no longer block the restore queue<\/strong>, preserving the parallel fetching those tags asked for.<\/li>\n<li>Fix: added a capability check to the notice-dismiss handler, and stopped the support notice marking itself dismissed simply by rendering.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release: interaction-delayed JavaScript, main-thread yielding, fallback timeout, exclusions, logged-in skip, and live INP\/long-task overlay.<\/li>\n<li>All output is escaped late, including the admin-notice nonce passed to inline JavaScript via wp_json_encode().<\/li>\n<li>Every function, option, and the localized config object uses the qfinp prefix to avoid conflicts with other plugins.<\/li>\n<\/ul>","raw_excerpt":"Lowers Interaction to Next Paint (INP) by delaying heavy JavaScript until the first user interaction and yielding the main thread between scripts.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/320255","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=320255"}],"author":[{"embeddable":true,"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/gunjanjaswal"}],"wp:attachment":[{"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=320255"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=320255"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=320255"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=320255"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=320255"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/rhg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=320255"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}