Skip to content

Releases: nrdmartinezz/CoreBoost

CoreBoost v3.3.10

Choose a tag to compare

@github-actions github-actions released this 13 May 18:09

🐛 Fixed - wp-core-shim Script Delayed Preload Discovery

  • Moved inject_wp_core_shims() hook from wp_head priority 0 to priority 3
  • The shim script was the first element output in <head>, pushing all preload/preconnect <link> tags lower in the HTML and delaying browser preload scanner discovery
  • New head order: preloads + preconnects (priority 1) → jQuery/font preloads (priority 2) → shim script (priority 3) → wp_print_scripts (priority 8)
  • Shim still fires well before after-inline-scripts (priority 8), preserving wp.i18n/wp.hooks/wp.domReady queue behaviour

CoreBoost v3.3.9

Choose a tag to compare

@github-actions github-actions released this 12 May 21:39

🔄 Reworked - cb-lcp Strategy: Preload-Only (Remove <img> Injection)

Root Cause Analysis

The <img> injection approach was based on a false premise. Elementor's video background
fallback image is applied as style="background: url(...) 50% 50%; background-size: cover;"
via server-side PHP (Group_Control_Background selectors). This means:

  1. The CSS background paints immediately without JS — it is not lazy-loaded or gated
    on Elementor adding .e-lazyloaded.
  2. The PSI "resource load delay" metric measures image discovery time, not paint-blocking
    JS. The browser only discovers CSS background-image URLs after downloading and parsing
    the stylesheet — this is what causes the delay.
  3. A <link rel="preload" fetchpriority="high"> in <head> is the direct and correct fix
    the preload scanner finds it during initial HTML tokenisation, before any CSS is fetched.
  4. Injecting a <img> as a child of the Elementor section was fighting Elementor's flex
    layout unnecessarily, causing double-height sections on desktop and size/overlap issues
    on mobile, with no benefit to the LCP metric.

Changes

  • inject_lcp_foreground_image() (Resource_Remover): removed <img> construction and
    injection entirely. The function now only extracts the image URL (via the 4-level cascade)
    and emits a <link rel="preload" as="image" fetchpriority="high"> before </head>. The
    section's opening tag is returned unmodified. No DOM changes, no layout impact.
  • output_lcp_img_styles() (Hero_Optimizer): removed method and wp_head hook — no
    <img> element exists to style.
  • define_hooks(): removed output_lcp_img_styles registration.
  • get_foreground_conversion_css(): .cb-lcp-img block updated to note removal.

What Still Fires

  • preload_video_hero() at wp_head priority 1 (via both preload_method dispatch and the
    unconditional enable_lcp_foreground_injection guard added in v3.3.7) — reads
    _elementor_data from DB and emits the preload tag early.
  • Output-buffer preload fallback in inject_lcp_foreground_image() — covers cases where
    preload_video_hero() misses the URL (e.g. non-standard Elementor structures).

Files Modified

  • includes/public/class-resource-remover.phpinject_lcp_foreground_image() img injection removed
  • includes/public/class-hero-optimizer.phpoutput_lcp_img_styles() removed; define_hooks() updated

CoreBoost v3.3.8

Choose a tag to compare

@github-actions github-actions released this 12 May 19:59

🐛 Fixed - cb-lcp-img Causing Double Height on Desktop / Wrong Size on Mobile

Root Cause

enqueue_optimization_styles() registered .cb-lcp-img CSS via
wp_add_inline_style('wp-block-library', ...). On Elementor sites wp-block-library is
typically never enqueued, so WordPress silently discarded the inline style. Without
position: absolute; inset: 0; width: 100%; height: 100% the injected <img> rendered
as a normal block element — adding its full intrinsic dimensions to the section height
(doubling it on desktop) and appearing as an overlaid, under-sized image on mobile.

Additionally, the parent element needed an explicit position: relative guarantee. Elementor
sections are usually position: relative, but without an enforced rule the absolute positioning
had no reliable containing block.

Changes

  • output_lcp_img_styles() added (Hero_Optimizer) — new wp_head priority-1 method that
    outputs a <style id="coreboost-cb-lcp"> tag directly into the document <head>. Bypasses
    wp_enqueue_scripts entirely, so the CSS is always delivered regardless of which stylesheets
    are registered. Only runs when enable_lcp_foreground_injection is on and not in admin/preview.
  • CSS rules: .cb-lcp { position: relative !important; overflow: hidden; } and
    .cb-lcp-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; pointer-events: none; display: block; }. The !important on position: relative
    prevents any theme or Elementor rule from stripping the containing-block guarantee.
  • define_hooks() — wired output_lcp_img_styles at wp_head priority 1.
  • get_foreground_conversion_css().cb-lcp-img block emptied (styles now owned by
    output_lcp_img_styles; legacy .hero-foreground-image / .heroimg rules unchanged).

Files Modified

  • includes/public/class-hero-optimizer.phpdefine_hooks(), new output_lcp_img_styles(), get_foreground_conversion_css()

CoreBoost v3.3.7

Choose a tag to compare

@github-actions github-actions released this 12 May 19:07

🐛 Fixed - LCP Preload Not Firing When preload_method Is Not video_hero

Root Cause

preload_video_hero() — which reads _elementor_data from the database and emits a
<link rel="preload" fetchpriority="high"> at wp_head priority 1 — was only called when
preload_method was explicitly set to video_hero or video_fallback. Sites using any
other preload method (e.g. automatic, css_class) received no <head> preload for the
video fallback image, causing the LCP resource load delay to remain.

Additionally, inject_lcp_foreground_image() Levels 1–3 could all miss when Elementor
applies the fallback background as an inline style via JavaScript (client-side) rather than
server-side PHP — so no URL was ever found and cb-lcp-img was not injected.

Changes

  • preload_hero_images() (Hero_Optimizer): after the normal preload_method dispatch,
    always calls preload_video_hero() when enable_lcp_foreground_injection is on. This
    implements Method A from the Manus AI research: an unconditional wp_head priority-1 preload
    tied to the enable_lcp_foreground_injection feature flag. output_preload_tag() deduplication
    prevents a double tag if video_hero is also the active preload_method.
  • inject_lcp_foreground_image() — Level 4 added (Resource_Remover): when Levels 1–3 all
    fail, reads _elementor_data post meta directly and scans the first 5 top-level Elementor
    elements for background_video_fallback.url (then background_image.url). This is the same
    database-level lookup used by preload_video_hero() and is immune to whether Elementor applies
    the inline style via PHP or JS. Result cached in closure scope — DB query runs at most once
    per page even when multiple cb-lcp elements are present.

Files Modified

  • includes/public/class-hero-optimizer.phppreload_hero_images() secondary dispatch
  • includes/public/class-resource-remover.phpinject_lcp_foreground_image() Level 4

CoreBoost v3.3.6

Choose a tag to compare

@github-actions github-actions released this 12 May 18:45

🐛 Fixed - LCP Foreground Injection (cb-lcp) Not Firing

Root Cause

inject_lcp_foreground_image() used a subcapture group for attribute extraction:
([^>]*\bclass=["\'][^"\']*\bcb-lcp\b[^"\']*["\'][^>]*). PCRE backtracking on the trailing
[^>]* could cause attributes such as data-coreboost-deferred-youtube or the inline style
to fall outside $matches[2], resulting in the function finding no image URL and silently
returning the original tag — so cb-lcp-img never appeared in the source.

A second cascading failure: even when smart_youtube_blocking was ON, the image URL was not being
found because Elementor applies the fallback as an inline CSS background on the wrapper element
(not in data-settings) and that path was never checked.

A third latent bug: start_output_buffer() only ran the output buffer when smart_youtube_blocking
or a script/CSS defer feature was active. If only enable_lcp_foreground_injection was on,
the buffer never started and injection never ran.

Changes

  • inject_lcp_foreground_image() fully rewritten. Outer regex simplified to
    /<[a-z][a-z0-9]*\s[^>]*\bcb-lcp\b[^>]*>/i — no subcapture groups. All four attribute
    extractions run directly on $matches[0] (the full opening tag string), eliminating the
    PCRE backtracking failure mode entirely.
  • 3-level image URL cascade:
    1. data-settings JSON → background_video_fallback.url then background_image.url
      (present when smart_youtube_blocking is OFF).
    2. data-coreboost-deferred-youtube JSON → fallback.url / fallback (string)
      (present when smart_youtube_blocking has stripped data-settings).
    3. Inline style attribute — per Elementor's architecture, the video fallback is
      rendered as style="background: url('...') 50% 50%; background-size: cover;" on the
      wrapper element by the Group_Control_Background CSS selector. This level is always
      present in the rendered HTML and was previously never read.
  • <link rel="preload"> now injected directly from inject_lcp_foreground_image(). After
    the preg_replace_callback pass, the first resolved image URL is injected as a
    <link rel="preload" fetchpriority="high"> before </head>. This makes the head preload
    independent of Hero_Optimizer::preload_video_hero() and the preload_method setting —
    so it fires correctly regardless of which hero detection method is configured.
  • start_output_buffer() gate extended to include
    !empty($this->options['enable_lcp_foreground_injection']). Previously the output buffer
    only ran when a script/CSS defer or smart_youtube_blocking feature was also active; disabling
    those features would silently prevent LCP injection from running at all.

Files Modified

  • includes/public/class-resource-remover.phpinject_lcp_foreground_image() full rewrite; start_output_buffer() buffer-start condition

CoreBoost v3.3.5

Choose a tag to compare

@github-actions github-actions released this 12 May 18:07

🐛 Fixed - LCP Resource Load Delay & Critical Request Chain

LCP Resource Load Delay (cb-lcp + YouTube video backgrounds)

  • inject_lcp_foreground_image() now reads the fallback URL from data-coreboost-deferred-youtube when data-settings has been cleared. process_inline_assets() calls remove_youtube_background_iframes() first, which strips background_video_fallback out of data-settings and moves it into the data-coreboost-deferred-youtube attribute. The subsequent inject_lcp_foreground_image() call then saw only {"background_background":"video"} in data-settings — no image URL — so no <img fetchpriority="high"> was injected into the LCP element. Without that native <img> the browser had no early signal to start fetching the fallback image, resulting in the 1,260 ms LCP resource load delay reported by PageSpeed Insights. The fix adds a secondary lookup: when data-settings yields no image URL, the function decodes data-coreboost-deferred-youtube and reads its fallback.url field. This ensures the high-priority LCP <img> is always injected on video-background containers that carry the cb-lcp class, moving LCP time from "resource load delay" into "resource load duration" where it belongs.

Critical Request Chain (dist/i18n.min.js)

  • wp.i18n / wp.hooks / wp.domReady compatibility shim injected at wp_head priority 0. When enable_wp_core_defer is on, the wp-i18n, wp-hooks, and wp-dom-ready scripts are deferred, but plugins like Elementor attach after-inline-scripts (via wp_set_script_translations() / wp_add_inline_script(..., 'after')) that call e.g. wp.i18n.setLocaleData() synchronously — before the deferred modules execute — causing a TypeError. The new inject_wp_core_shims() method (hooked at wp_head priority 0) installs a Object.defineProperty setter-based proxy on each global (wp.i18n, wp.hooks, wp.domReady). Inline callers see a lightweight stub that queues their calls; when the deferred module writes the real implementation to the property the setter fires, replays every queued call, then removes itself so the property behaves normally from that point.
  • Removed the has_inline_scripts() guard from the enable_wp_core_defer defer path. Previously, the presence of ANY inline script attached to wp-i18n (including just localized data) blocked deferral entirely, leaving dist/i18n.min.js as a render-blocking resource in the critical request chain. The shim now handles the safety concern, so the guard is removed and the scripts are always deferred when enable_wp_core_defer is enabled.
  • /dist/i18n, /dist/hooks, /dist/dom-ready removed from URL-level skip list in get_url_exclusions(). The old broad patterns accidentally prevented Elementor's own dist/i18n.min.js (served under /plugins/elementor/) from being deferred by defer_scripts_by_url. Replaced with full /wp-includes/js/dist/ paths so only the actual WordPress core files are skipped at the URL level; Elementor's i18n bundle is now correctly deferred by the /elementor/ pattern in should_defer.
  • /wp-includes/js/dist/i18n, /wp-includes/js/dist/hooks, /wp-includes/js/dist/dom-ready removed from the hard-coded $critical_wp_scripts array in process_inline_script_callback(). With the shim in place these scripts are safe to defer; the URL-level guard was redundant and was preventing URL-based deferral when the handle-based path didn't fire.

Files Modified

  • includes/public/class-resource-remover.phpinject_lcp_foreground_image(): fallback lookup from data-coreboost-deferred-youtube; get_url_exclusions(): tightened /dist/i18n|hooks|dom-ready skip patterns; process_inline_script_callback(): removed wp-i18n/wp-hooks/wp-dom-ready from $critical_wp_scripts
  • includes/public/class-script-optimizer.phpdefine_hooks(): new wp_head priority-0 hook; new inject_wp_core_shims() method; defer_scripts(): removed has_inline_scripts() guard for enable_wp_core_defer handles

CoreBoost v3.3.4

Choose a tag to compare

@github-actions github-actions released this 12 May 03:04

🐛 Fixed - Tag Manager Plain Text Output & GTM Detection Failure

  • document.importNode(template.content, true) replaces template.innerHTML + div.innerHTML round-trip in output_delay_script(). Reading .innerHTML from a <template> element serializes its inert DocumentFragment back to an HTML string. Re-assigning that string to a div.innerHTML re-parses it in the live (scripting-enabled) document, where <noscript> is treated as a raw-text element — its child <iframe> becomes a literal text node that renders as visible markup on the page. document.importNode(template.content, true) clones nodes directly from the inert fragment with no serialization, preserving <noscript> structure correctly. Applied to all three tag blocks (head, body, footer).
  • .textContent replaces .innerHTML for inline script content copies. When recreating <script> elements in the delay injector, content was read/written via .innerHTML. The HTML serializer encodes characters such as & (present in GTM's '&l='+l snippet) to &amp;, corrupting the script and causing Google Tag Assistant to fail to detect the tag. Switching to .textContent bypasses HTML serialization entirely.

Files Modified

  • includes/public/class-tag-manager.phpoutput_delay_script() head, body, and footer tag injection blocks

CoreBoost v3.3.3

Choose a tag to compare

@github-actions github-actions released this 12 May 01:44

🐛 Fixed - Tag Manager Breaking Google Analytics & Third-Party Scripts

  • <script type='text/template'> wrapper replaced with <template> for delayed head/body/footer tags. The HTML spec treats every <script> element as raw text terminated by the first </script> string it encounters, regardless of the type attribute. This caused the CoreBoost delay wrapper to be prematurely closed by the first </script> present inside a stored snippet (e.g. a GA4 / GTM tag that contains its own </script>). All content after that closing tag was emitted as loose, malformed HTML — breaking Google Analytics and any other multi-tag tracking snippets. Replacing the wrapper with a <template> element resolves this because <template> content is parsed as real HTML (not raw text), so inner </script> tags do not terminate the container. <template> is valid in <head>, its content is inert until explicitly moved, and it is universally supported.
  • Inline delay script updated to read innerHTML from <template> elements. The three loadCoreBoostTags() content reads (headTags, bodyTags, footerTags) previously used .textContent || .innerText, which is the correct API for <script> raw text. <template> exposes its parsed document fragment via .innerHTML, so all three reads are updated accordingly.

Files Modified

  • includes/public/class-tag-manager.phpoutput_head_tags(), output_body_tags(), output_footer_tags() PHP wrappers; output_delay_script() JS content reads

CoreBoost v3.3.2

Choose a tag to compare

@github-actions github-actions released this 11 May 21:46

✨ Added - LCP Foreground Injection (cb-lcp)

  • cb-lcp CSS class convention for Elementor sections. Add cb-lcp to any Elementor section or container's Advanced → CSS Classes field. CoreBoost detects the class in the output buffer and injects an <img fetchpriority="high" loading="eager" class="cb-lcp-img"> as the first child of that element. This gives the browser a native <img> LCP target, bypassing Elementor's lazy-load CSS gate (background-image: none !important until .e-lazyloaded is added by deferred JS).
  • Image URL resolved from Elementor data-settings. The injected <img> uses the element's background_video_fallback.url (preferred — the image shown before/during video load) falling back to background_image.url. The <link rel="preload"> emitted by Hero_Optimizer is also updated to prefer the video fallback URL when cb-lcp is present, so preload and LCP element always point to the same file.
  • .cb-lcp-img CSS — absolutely positioned, inset: 0, width/height: 100%, object-fit: cover, z-index: 0, pointer-events: none. Sits behind Elementor's overlay (::before) and the video container without interfering with layout or interaction.
  • New setting: enable_lcp_foreground_injection — checkbox under Hero Image & LCP Optimization. Off by default.

🐛 Fixed - Remove Unused CSS/JS Pattern Matching

  • remove_unused_styles() and remove_unused_scripts() now support the same pattern syntax as CSS/JS defer. Previously both methods did a strict wp_style_is() / wp_script_is() exact-handle lookup, so patterns like widget-, elementor-post-, or swiper (which work in the defer fields) silently matched nothing. The methods now iterate $wp_styles->registered / $wp_scripts->registered and apply the same four-tier matching: exact, trailing-dash prefix, wildcard (*), and partial/contains. Extracted into a shared handle_matches_pattern() helper.

Files Modified

  • includes/public/class-hero-optimizer.phpsearch_elementor_hero_advanced() cb-lcp detection; get_foreground_conversion_css() .cb-lcp-img rules; enqueue_optimization_styles() gate
  • includes/public/class-resource-remover.phpinject_lcp_foreground_image() new method + call in process_inline_assets(); remove_unused_styles() / remove_unused_scripts() pattern matching rewrite; new handle_matches_pattern() helper
  • includes/core/class-config.phpenable_lcp_foreground_injection field config
  • includes/class-coreboost.phpenable_lcp_foreground_injection runtime default
  • includes/class-activator.phpenable_lcp_foreground_injection install default
  • includes/core/class-migration.phpenable_lcp_foreground_injection migration default
  • includes/admin/class-settings-registry.php — LCP Foreground Injection field registered
  • includes/admin/class-settings-sanitizer.php — added to boolean list and hero field map
  • includes/admin/class-settings-page.php — added to hidden-fields preservation list
  • includes/admin/class-cache-page.php — added to preserved fields list

CoreBoost v3.3.1

Choose a tag to compare

@github-actions github-actions released this 10 May 07:26

🐛 Fixed - Smart YouTube Blocking Never Activating & Video Hero Ignoring Page-Specific Images

  • smart_youtube_blocking runtime defaults corrected. The v3.3.0 fix only updated class-config.php, which drives the admin settings UI field default — not the actual option values used at runtime. class-activator.php (fresh installs), class-coreboost.php (runtime merge fallback), and class-migration.php (merge_option_defaults()) all still had false. Because array_replace($defaults, $saved_options) always lets the saved DB value win, any site installed before the option existed had false persisted in the database and the feature never ran despite appearing enabled. All three runtime defaults are now true, and a new migrate_to_3_3_1() step explicitly writes true into coreboost_options for every site upgrading from < 3.3.1.
  • Page-specific image overrides now respected in video_hero preload mode. preload_video_hero() went straight to Elementor data detection without first consulting the specific_pages setting, so any manual override entered in the page-specific images field was silently skipped. The method now checks specific_pages first — emitting the override preload and returning early — before falling through to Elementor fallback detection. Matches the behaviour of preload_automatic().

Files Modified

  • includes/class-activator.phpsmart_youtube_blocking default falsetrue
  • includes/class-coreboost.phpsmart_youtube_blocking default falsetrue
  • includes/core/class-migration.phpsmart_youtube_blocking default falsetrue; new migrate_to_3_3_1() migration step
  • includes/public/class-hero-optimizer.phppreload_video_hero() now checks specific_pages overrides before Elementor detection