Recent Activities

This page shows what are we working on.

swissup / module-pagespeed

2 days ago success
  • 1.18.4
    • Version 1.18.4

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> aa4b80

    • Merge pull request #102 from swissup/fix/requirejs-bundle-pool-order-27428

      fix(defer): keep the bundle pool and our RequireJS patches in place 7aeb97

    • test: repair the typo'd DOCTYPE in the offset fixture

      `<!` followed by a space is not a doctype, so libxml parsed it as a bogus
      comment. With LIBXML_HTML_NOIMPLIED the parser then had no document element to
      attach the real <html> to, emitting "misplaced <html> tag"; Magento's unit
      bootstrap promotes that warning to an exception, so the test errored on every
      run instead of asserting anything.

      Also close the space inside the require.js src in the same fixture. That one did
      not fail the test — the assertions only count //script[@src] and compare their
      offsets — but the path was meaningless as written.

      The three other fixtures in this file already spell the doctype correctly.

      Fixes #103

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> cdbf37

    • fix(defer): narrow the RequireJS patch guard to override.js

      The bootstrap guard matched the whole Swissup_Pagespeed/js/lib/requirejs/
      directory, which pinned preload-all-scripts.js in <head> as well. That file is
      not bootstrap: addPreloadAllScripts() add()s it at the end of the asset
      collection rather than inserting it after the min resolver, and its entire body
      runs inside a window load handler, so it cannot race require.config(). Guarding
      it only costs a render-blocking head script on stores with Force RequireJS
      Loading enabled.

      Match 'Swissup_Pagespeed/js/lib/requirejs/override' instead, and correct the
      comment: it described insert()-after-min-resolver placement that applies to
      override.js alone.

      testPreloadAllScriptsStaysOptimizable pins the reverse direction - the file must
      still move to body end and take async past the counter threshold. It fails with
      the directory-wide prefix and passes with the narrowed one.

      Also assert asset presence while collecting positions in
      testLiveHeadKeepsBootstrapChainInOrder: strpos returns false for a dropped
      asset, which asort() sorts first, reporting a bogus ordering violation instead
      of the missing script.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 5e0e10

    • fix(defer): keep the bundle pool and our RequireJS patches in place

      The 1.18.2 bootstrap guard was meant to cover the bundled module pool, but
      'js/bundle/bundle' only matches Magento's own bundle0.js. Advanced JS Bundling
      names its pool after the layout handle -- default-bundle0.js,
      cms-page-view-bundle0.js -- so none of our bundles ever matched, and
      Swissup_Pagespeed/js/lib/requirejs/override.js was not listed at all.

      Combined with the 1.18.2 counter change, where skipped-but-executable scripts
      consume a slot, these scripts crossed the jsCounter > 5 threshold and started
      getting async -- something that did not happen before 1.18.2. Both call
      require.config(): the bundle pool registers the jsbuild sources, and override.js
      wraps require.config() and must be installed before requirejs-config calls it.
      So on a store running Advanced JS Bundling or Interactive Defer, 1.18.3
      introduced a fresh instance of the very failure class it fixed.

      Match the whole js/bundle/ directory instead of a filename prefix (anything
      living there is a module pool by construction) and add our own RequireJS patch
      directory.

      Regression coverage uses the head sequence dev2.dlastore.com actually serves,
      with both features on: six ignored third-party inline blocks, the global require
      config, then Magento's bootstrap interleaved with the bundle pool. The fixture
      asserts the whole chain stays ahead of the body content, carries no async/defer,
      and keeps its document order. It fails in seven places without the fix.

      Refs TTF-27428

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 1b477c

  • 1.18.3
    • Version 1.18.3

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 82a806

    • Merge pull request #101 from swissup/fix/requirejs-bootstrap-coverage

      fix(defer): cover every RequireJS bootstrap asset and stop counter drift 5a4389

    • fix(defer): count only executable scripts and cover global require config

      Three follow-ups on the previous commit in this branch.

      Counting every skipped script restored bootstrap coverage but also counted
      inert blocks. text/x-magento-template, text/html and JSON payloads are never
      executed by the browser, and Magento emits a handful of them on most pages
      (minicart, checkout, swatches). Counting them inflated jsCounter and pushed
      later scripts past the async (> 5) and third-party defer (> 1) thresholds, so
      scripts that used to stay synchronous started getting async and losing their
      execution order. jsCounter now advances only for script tags the browser
      actually runs: an empty type, a JS MIME type, or the configured delayed type
      (those are executed by the delayed-script runtime, so they keep their slot).

      The inline bootstrap matcher only recognized the require.config() call. The
      other legitimate form, a global `var require = {...}` / `window.require =
      {...}` object emitted before require.js loads, carries the same
      baseUrl/paths/map data and is under the same ordering constraint, so it was
      still relocated behind the content and reproduced TTF-27428 on themes that
      use it. Added REQUIREJS_INLINE_GLOBAL_PATTERN.

      Inline matching is textual, not parsed, so a script mentioning the config
      statement inside a string or a comment is opted out too. That direction is
      deliberate - a missed optimization instead of a broken RequireJS bootstrap -
      but it was documented as if only src matching had that property. Corrected the
      docblock and pinned the behaviour with a test. Also gated both patterns behind
      a stripos() check, since the matcher runs on every inline body including the
      multi-hundred-kilobyte checkoutConfig payload.

      Tests: 35 -> 42. Verified against the pre-fix code: 6 failures, one per gap
      (inert-counter case plus five global-config spellings). With this change
      705/705 green, phpcs 0 errors.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> ee4c79

    • fix(defer): cover every RequireJS bootstrap asset and stop counter drift

      PR #99 protected only requirejs/require.js, mage/requirejs/mixins.js and
      requirejs-config.js. Magento renders up to eight bootstrap assets in <head>
      (Magento\RequireJs\Block\Html\Head\Config::_prepareLayout), and the rest were
      still relocated to the end of <body>:

      - requirejs-min-resolver.js patches ctx.nameToUrl to append the .min sign and
      is emitted whenever JS minification is on, i.e. in production
      - mage/requirejs/baseUrlResolver.js + requirejs-map.js install the URL map
      - mage/requirejs/static.js and js/bundle/bundle*.js define the module pool

      Moving any of them behind the content reproduces the same failure class as
      TTF-27428: module ids resolve against the bare baseUrl and static URLs are wrong.

      Replace the five ignore signatures with isRequireJsBootstrap(), which matches
      external assets on src only (an unrelated script merely mentioning a bootstrap
      path in its code is no longer opted out of deferring) and inline blocks on the
      require.config()/requirejs.config() call itself, tolerant to any spacing.

      Also increment jsCounter for skipped scripts. Without it every ignore signature
      shifted the unpack/async/defer thresholds of later scripts: with PR #99 only
      three of six eligible inline scripts were still delayed on a page whose <head>
      carries the bootstrap.

      Extend RequireJsBootstrapOrderRegressionTest with a provider over all eight
      minified asset names, seven inline-config spellings, a guard that a script only
      mentioning a bootstrap path stays optimized, and a counter-stability assertion.
      Against the previous code the new cases produce 9 failures; with this change the
      suite is 698/698 green.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 8ae870

    • Merge pull request #100 from swissup/fix/category-image-swap-xss-14036

      fix(image): keep the processed marker out of the DOM (#xss-14036) 374f33

    • fix(dom): rank class last in attribute matching (#xss-14036)

      Follow-up on review of the processed-marker fix.

      AttributeBasedStrategy tried `class` before `src`, which is what let the
      production patch land on a foreign product image in the first place. The
      ambiguity guard alone does not cover a class that matches exactly one -
      but wrong - element, so order the attributes from most to least
      identifying and keep `class` as the last resort. Testing for a second
      match from the first match's offset replaces the full-document
      preg_match_all, and a skipped match is now logged instead of silently
      dropping the optimization.

      ProcessedNodeRegistryTrait no longer requires the consuming class to call
      an initializer from its constructor: the storage is created on first use,
      so a reader can never hit an uninitialized typed property. Added __clone
      so a cloned document gets its own registry, and documented that entries
      are keyed by PHP object identity and do not survive a node being rebuilt
      from HTML.

      PipelineCategoryImageSwapTest claimed to reproduce the image swap. It
      does not: in a fixture that small OffsetBasedStrategy still resolves the
      orphaned patch group, so AttributeBasedStrategy is never reached and no
      image is swapped. Its src assertions are non-regression guards; what is
      actually red before the fix is the dropped Lcp patch and the leaked
      marker. Docblock now says so, and the swap stays pinned at unit level.

      Tests: 673 tests, 2030 assertions, OK.
      phpcs --standard=Magento2 on the touched files: 0 errors.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 5e9d02

    • fix(image): keep the processed marker out of the DOM (#xss-14036)

      On a category page the first two product images were rendered with each
      other's <img> tag. Reproduced on mcprod.boutinot.com/wines.html: item 1
      links to CHV722 but shows CHV726, item 2 the reverse. Only the two images
      that LCP marks with fetchpriority="high" were affected, and the wrong
      output was then stored in the full page cache.

      markImageAsProcessed() set data-pagespeed-processed through the raw
      \DOMElement::setAttribute(), so the mutation was never recorded as a patch.
      That made the oldHtml of every later patch of the same node stale, so
      PatchGrouper could not chain it and the patch fell through to the fuzzy
      replacement strategies. AttributeBasedStrategy then matched by
      class="product-image-photo" - shared by every product image - and rewrote
      the first product image with the second product's HTML.

      Keep the marker in an SplObjectStorage registry on TrackedDomDocument
      instead of in the DOM, and stop AttributeBasedStrategy from matching by a
      class that several elements share. A patch that fails to apply only loses
      an optimization; a patch applied to the wrong element corrupts the page.

      Side effect: data-pagespeed-processed no longer appears in page output.
      Nothing in JS, templates or tests reads it.

      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> c5b7a3

swissup / module-ajaxsearch

2 days ago success
  • head
    • Fixed layout shift when result list is long 8715cc

    • Fixed overflowed content in Firefox (Apollo theme) de660b

    • Merge pull request #57 from swissup/phpunit12-test-api-56

      Migrate Test/Unit off removed PHPUnit APIs (PHPUnit 12 / PHP 8.5) 095093

    • test: migrate removed test APIs for PHPUnit 12 / PHP 8.5

      The CI runner targets PHP 8.5, which requires PHPUnit 12.x. Migrate the
      unit tests off APIs removed in PHPUnit 10-12:

      - setMethods() (removed v10) -> onlyMethods(); all mocked methods verified
      to exist on the target class via reflection. Dropped dead duplicate mock
      builders (Magento CollectionFactory immediately overwritten by the
      Swissup one).
      - getMockForAbstractClass() (removed v12) -> createMock().
      - will($this->returnValue()/returnSelf()/onConsecutiveCalls()) (removed
      v12) -> willReturn()/willReturnSelf()/willReturnOnConsecutiveCalls().
      - Non-static data providers (hard error v12) -> public static function.

      Also fixed two removed APIs not listed in the issue but caught while
      running the suite:

      - $this->at() (removed v10) in DataTest and ProductTest -> willReturnMap()
      / atLeastOnce() / consecutive-call stubs.

      InitTest was stale independently of PHPUnit: it exercised a removed
      getClassNames() method and the old constructor/getSettings signature.
      Realigned it to the current Init block and dropped the redundant
      getClassNames test (already covered by Helper\DataTest).

      Verified: 41 tests, 99 assertions, 0 errors, 0 deprecations on
      PHPUnit 10.5 / PHP 8.3 (`bin/test`).

      Refs swissup/module-ajaxsearch#56

      Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> 20854c

    • test: add module-local PHPUnit runner

      Add bin/test and phpunit.xml.dist so the unit suite can be run in
      isolation via `bin/test` (runs vendor/bin/phpunit inside the container),
      mirroring the setup already present in module-askit. .gitignore keeps the
      PHPUnit result cache out of the repo.

      Refs swissup/module-ajaxsearch#56

      Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> a4e899

swissup / module-firecheckout-integrations

4 days ago success

swissup / testimonials

4 days ago success

swissup / module-testimonials

4 days ago success

swissup / module-ignition

4 days ago error
  • 1.3.2
  • 1.3.1
    • Merge pull request #7 from vinai-drive-by-commits/ai-friendly-error-page

      Add copy buttons for the stack trace and message to the error page f73b13

    • Add copy buttons for the stack trace and message to the error page

      Two buttons in the bottom-right of the error page copy either a
      PHP-style stack trace (exception class, message and frames) or just
      the exception message, so an error can be quickly searched for or
      handed to an AI assistant. Cmd/Ctrl+C copies the full stack trace as
      well, unless the user has selected some text themselves.

      The same text is exposed for browser-automation agents without going
      through the clipboard: a `window.swissupIgnition` object
      ({ report, message, stackTrace, copyStackTrace(), copyMessage() }) and
      hidden DOM nodes `#swissup-ignition-stacktrace` /
      `#swissup-ignition-message` that can be read via textContent.

      The widget is injected through Spatie's addCustomHtmlToBody() and built
      with the DOM API (no injected <style>, no inline event handlers) to stay
      compatible with the script-nonce CSP the module applies to the page. 163a07

    • Fixed missing error modal on failed ajax request, when `global:false` 915a01

swissup / module-quantity-switcher

4 days ago success
  • head
    • Merge pull request #5 from swissup/fix/arrow-room-lost-after-mount

      fix(arrows): keep the arrow room after the switcher mounts 1a9480

    • fix(arrows): keep the arrow room after the switcher mounts

      `.control:has(> .input-text.qty)` only matches the server-rendered markup.
      `product.js` wraps the input into `.qty-wrapper` on init, after which the input
      is no longer a direct child of `.control`, the rule stops matching and the 20px
      reserved on each side for the arrows disappears — the arrows overflow the field
      and the layout shifts once JS runs.

      Match the input as a descendant instead, which holds both before and after the
      wrap. Verified in the browser: `.control` padding went `0px 20px` -> `0px` the
      moment the wrapper was inserted, and stays `0px 20px` with this selector.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 082597

  • 1.2.3
    • Version 1.2.3 f2d44f

    • Fixed MSI error for bundle products (with no MSI source) on the cart page aa1c46

swissup / argento-420shop

4 days ago success
  • head
    • Merge pull request #21 from swissup/fix/quickview-qty-clipping

      fix(qty): stop quick view clipping quantities of 10 or more 541862

    • fix(qty): stop quick view clipping quantities of 10 or more

      The qty switcher styles were nested inside `.catalog-product-view`, but the
      Ajaxpro quick view renders the same product markup on category and search
      pages, where that body class is absent. In the popup the input therefore fell
      back to breeze's `max-width: 4rem` (64px) while keeping the legacy
      `padding: 5px 34px 5px 15px` — leaving an 11px content box. At 18px font that
      is one digit, so every value >= 10 rendered as its first digit only.

      Scope both the input sizing and the switcher arrows to
      `.product-info-wrapper` instead, and drop the 34px right padding: it reserved
      room for an in-input arrow design that no longer exists — the arrows are
      absolutely positioned outside the field. Verified on the live dev store:
      content box goes 11px -> 64px, `scrollWidth` no longer exceeds `clientWidth`
      for 10, 20 or 100.

      The padding rule is now specific enough (0,4,0) to win over the stale
      `.product-info-main .input-text.qty { padding: 5px 34px 5px 15px }` still
      present in the theme editor CSS.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 439222

  • v1.8.0
    • Version v1.8.0 dcc43a

    • feat(faq): card-style two-column FAQ accordion like reference design

      Turn the RichSnippets FAQ accordion into white rounded cards laid out
      in a two-column grid on desktop (single column on mobile), matching
      the stigefabrikken.dk reference more closely.

      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> 0cf16e

    • feat(faq): style KB listing and RichSnippets FAQ widgets via CSS vars

      Override CSS custom properties of Swissup_KnowledgeBase listing widget
      (--kb-faq-*, module >= 1.1.44) and Swissup_RichSnippets FAQ accordion
      (--faqs-*) to match the stigefabrikken.dk reference design: bottom
      borders between items, semibold questions, accent-color hover.

      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> c0f2c4

swissup / module-easybanner

5 days ago success
  • head
    • Installer. Assign one banner to multiple placeholders 721496

    • Revert "update Marketplace installer commad to assign existing banner to the placeholder."

      This reverts commit 054e032d04fd358089648872fb47cccbdf1da3f4. c9476e

    • Revert "update Marketplace installer commad to assign existing banner to the placeholder."

      This reverts commit 054e032d04fd358089648872fb47cccbdf1da3f4. a464ee

    • update Marketplace installer commad to assign existing banner to the placeholder. 054e03

swissup / theme-stigefabrikken-breeze

5 days ago error