alleyinteractive/wp-asset-manager
A WordPress library for registering and enqueueing theme and plugin assets from build-tool manifests, handling versioning, dependencies, and cache busting so compiled scripts and styles load reliably.
Architecture fit. wp-asset-manager is a WordPress plugin, not a framework-agnostic PHP library, so its fit with a Laravel codebase is indirect: it earns a place only in hybrid estates where WordPress serves content alongside (or inside) a Laravel application — Roots/Sage or Bedrock themes, WordPlate-style integrations, or a Laravel app fronting a headless WP instance. In that context its value proposition is narrow but real: it centralises async/defer/PRPL asset loading, preload hints, and SVG sprite injection behind a small am_* helper surface, which is exactly the class of code teams otherwise hand-roll per project. For a pure Laravel application with no WordPress runtime, this is not a candidate — Vite, Laravel Mix, or a @preload directive already cover the same ground with first-class framework support.
Integration feasibility. The v2.0.0 surface is stable and predictable: five load methods (sync, async, defer, inline, preload), plus a strategy bridge into core's WordPress 6.3+ enqueue argument. The release materially improves integration ergonomics — am_modify_load_method() now accepts array|string consistently with other helpers (previously a TypeError on the documented array form), deps are now honoured for self-printed assets with transitive ordering, and imagesrcset/imagesizes/fetchpriority land in am_preload() for responsive LCP images. Those last two are the highest-leverage additions for a performance-oriented rollout. Against that, the breaking surface is substantial for a major bump: PHP 8.3 and WP 6.3 floors, the async-defer method removed, five Scripts::* methods removed, two Asset_Manager properties removed, preload removed from am_enqueue_style(), and the text domain renamed.
Technical risk. Moderate-to-high for existing installs, low for greenfield. The dominant risks are behavioural rather than syntactic: (1) the stylesheet defer → async collapse changes when the download starts, moving from post-DOMContentLoaded to during HTML parsing, which can shift perceived render on above-the-fold content and needs visual regression coverage, not just unit tests; (2) unrecognised load methods now raise _doing_it_wrong() instead of silently falling back to sync, so latent typos in third-party or legacy code become log noise or visible notices under WP_DEBUG_DISPLAY; (3) the dependency-ordering fix, while correct, changes print order for previously-registered assets, which can perturb CSS cascade outcomes in edge cases. The upside risk mitigations are strong: PHPStan level 9, linted tests with #[CoversClass], a CI matrix across PHP 8.3–8.5 and a dedicated minimum-WP job, and a forward-compatibility fix for WordPress 7.0's wp_kses_hair() rebuild. The explicit alleyinteractive/composer-wordpress-autoloader dependency fixes a genuinely dangerous failure mode where a fresh composer install could not autoload the plugin's own classes — that alone justifies treating this as a required upgrade rather than an optional one.
Key questions. What is our installed-base distribution of PHP and WordPress versions, and which client sites sit below the 8.3/6.3 floor? Which code paths reference Scripts::$async_scripts, add_to_async(), add_attributes(), disable_concat(), manage_async(), $assets_by_dependency, or $assets_manual? Do any themes depend on the bundled loadCSS behaviour or on the pre-0.1.1 style preload method? Are there shipped translation files keyed to the am domain that will silently stop resolving? What is the project's support window for the 1.x line, and is there a stated removal timeline for the am_* template tags beyond "next major"?
Stack fit. Treat this as a WordPress-tier dependency in a hybrid architecture, version-pinned and isolated from the Laravel application tier. In a Sage/Bedrock setup it installs via Composer and sits naturally in the theme's asset pipeline; in a headless configuration it belongs on the WordPress side only, with no expectation that Laravel's front end benefits from it. Teams should confirm the PHP floor (8.3) is already met by the Laravel runtime before co-locating both in one image, otherwise the plugin silently becomes the highest constraint in the estate.
Migration path. Upgrade in a branch, not incrementally in place, because the removals are hard breaks rather than deprecation shims — except for am_* template tags, which survive 2.x. Static analysis is the fastest inventory tool: run PHPStan against application code with the plugin's stubs to surface calls to removed Scripts methods and property accesses; grep handles load-method string literals ('async-defer', style 'preload', style 'defer'). Replace async-defer with core's strategy-backed async or defer per asset. Remove any manual loadCSS enqueues — the library is archived upstream and no longer shipped, so leaving a stale enqueue is now a hard dependency on code that isn't there. Regenerate translation files against the wp-asset-manager domain and re-run any wp i18n make-pot/make-mo step in CI. Finally, add the alleyinteractive/composer-wordpress-autoloader requirement explicitly if any downstream package pinned mantle-framework/testkit below v1.21.0.
Compatibility. The plugin now tracks core's own strategy argument rather than reimplementing async/defer, which means behaviour converges with WordPress instead of diverging — a good long-term posture and a reason to complete the upgrade rather than defer it. Note the CI now boots against SQLite rather than MySQL/Redis/Memcached: that is a maintainer-side simplification, but it means the project's own test signal no longer exercises persistent-object-cache or database-specific paths. For teams with object caching in production, add a smoke test in the real environment rather than trusting upstream green.
Sequencing. (1) Confirm PHP 8.3 / WP 6.3 floors and pin Composer constraints; (2) resolve the autoloader dependency and verify a clean composer install from a fresh clone; (3) inventory and replace removed APIs and load methods; (4) apply the stylesheet defer → async migration with visual regression and Core Web Vitals capture before/after; (5) enable fetchpriority/imagesrcset preloading for LCP images as a separate, measurable change; (6) re-verify SVG sprite rendering on pages that previously logged array-to-string or null-offset warnings; (7) open a tracked work item for am_* template tag migration ahead of the next major.
Maintenance. Net positive. PHPStan level 9 plus linted, #[CoversClass]-scoped tests raise the floor on contribution quality, phpcs.xml.dist allows local overrides, and CONTRIBUTING.md formalises the process. The two excluded WPCS sniffs are defensible and documented: PrefixAllGlobals enforces a four-character prefix the plugin's published am_ doesn't meet, and EnqueuedResources would flag exactly the direct <link>/<script> printing that async and defer require. Both exclusions should be recorded in our own review notes so a future auditor doesn't read them as sloppiness.
Support. Documentation moved from the README to the wiki — an external surface we don't version or vendor. That is a real support-cost shift: troubleshooting now depends on network access to a wiki that can change independently of the pinned package version. Mirror the API reference we depend on into internal docs at pin time. Support tickets should also be expected for the text domain rename, since translated admin strings will fall back to English until locales are refreshed. The am_* deprecation means we should budget a follow-on migration project now rather than treating it as future work.
Scaling. The preload additions (imagesrcset, imagesizes, fetchpriority) are directly relevant to Core Web Vitals at scale and are the version's strongest argument for adoption on high-traffic content sites. The dependency-ordering fix eliminates a class of non-deterministic load failures where self-printed assets raced their own dependencies — a latent issue that scales with page complexity. Removing the loadCSS shim reduces shipped JS, and dropping the CI containers reduces upstream build cost (indirectly ours, if we fork or vendor).
Failure modes. Watch for: _doing_it_wrong() notices surfacing on production if WP_DEBUG_DISPLAY is ever enabled with an unrecognised load method; FOUC or layout shift from the deferred-stylesheet timing change; silent sprite degradation now that create_symbol() returns null instead of emitting warnings (missing or unreadable SVG files fail quietly); removed static methods producing fatals on any code path the inventory missed; and autoload breakage on fresh installs in downstream projects that never declared the autoloader. The fatal-error fix for assets enqueued with a nonexistent function is a meaningful reliability win, but it also removes a previously loud signal — add coverage for that path. Rollback is straightforward: 2.0.0 is a clean pin revert provided no code depends on the new fetchpriority or imagesrcset options, so land those in a separate commit from the version bump.
Ramp-up. Low for engineers already fluent in WordPress enqueue semantics; moderate for Laravel-first developers, who will need to learn core's strategy argument to understand why the plugin no longer ships its own fallback. The moved API reference and the larger breaking section raise the cost of the first upgrade but lower it thereafter — post-2.0 the plugin is aligned with core rather than shadowing it. Plan roughly a half-day of inventory plus one to two days of remediation and visual verification for a typical Sage/Bedrock theme, with additional time proportional to how many load methods and Scripts::* calls the inventory surfaces.
How can I help you explore Laravel packages today?