Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jetpack Autoloader Laravel Package

automattic/jetpack-autoloader

A custom Composer autoloader for WordPress plugins that prevents package version conflicts by building an in-memory classmap and always loading the latest available version of each class, no matter which plugin loads it.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a Laravel package in the usual sense — it has no service provider, no config file, and nothing to register in config/app.php. It is a build-time autoloader generator plus a runtime shim for WordPress plugins that bundle Composer dependencies. If you are a Laravel developer, your day-to-day use of it is almost certainly one of two things:

  1. You maintain a WordPress plugin (or a shared library consumed by WordPress plugins) that ships Composer dependencies and must survive another plugin bundling the same dependency at a different version.
  2. You are evaluating it to understand why your WordPress plugin breaks intermittently when another plugin is active.

Either way, treat it as packaging infrastructure, not application code.

Minimal setup — in the plugin's composer.json:

{
    "require": {
        "automattic/jetpack-autoloader": "^5"
    },
    "config": {
        "vendor-dir": "vendor"
    }
}

The vendor directory must be the default vendor — the generated entrypoint hardcodes its own relative location assumptions.

Then:

composer install --no-dev --optimize-autoloader

In your main plugin file, bootstrap through the generated entrypoint instead of vendor/autoload.php:

require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload_packages.php';

Where to look first

  • vendor/autoload_packages.php — the shim your plugin file requires. Read it once; it shows the Autoloader class being invoked and the JETPACK_AUTOLOAD_* constants it probes.
  • vendor/composer/jetpack_autoload_classmap.php — the generated classmap, including package version numbers per entry. This is the file to inspect when the "wrong" version of a class is loading.
  • vendor/composer/jetpack_autoload_filemap.php — the equivalent for files autoload entries.

First use case to validate: install two copies of the same plugin-ecosystem dependency at different versions, activate them together, and confirm the newer class wins. If you only ever activate one plugin, you will never observe the behaviour this package exists for — and you will also never see its failure modes.

Implementation Patterns

Single owner, many consumers. The standard pattern is one plugin per site bundles the autoloader, but every plugin that requires the shared dependency also bundles it. The package only guarantees "latest version wins" when all plugins in the set use this autoloader. One plugin using stock Composer autoloading breaks the contract for the whole site.

Always ship an optimized build. Run composer install -o / composer dump-autoload -o in your release pipeline. With -o, PSR-4 and PSR-0 namespaces are converted to classmaps, which is what the version-resolution logic operates on. Unoptimized builds only convert PSR-0 to classmap and leave PSR-4 as a runtime prefix lookup, which weakens the version-resolution guarantees.

Use classmap autoloading for your own code too. The package's own guidance is that new code should use classmap autoloading so filenames can follow WordPress Coding Standards (class-my-thing.php) rather than PSR-4's MyThing.php. In practice:

{
    "autoload": {
        "classmap": ["src/"]
    }
}

and let -o do the work. This also means your file layout is not part of your public API, which is useful when the same class is bundled by multiple plugins.

Defer everything to plugins_loaded. Do not instantiate package classes at file scope in your main plugin file. Hook your bootstrap:

require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload_packages.php';

add_action( 'plugins_loaded', function () {
    ( new My_Plugin\Bootstrap() )->run();
} );

The autoloader needs every participating plugin to have been registered (via plugins_loaded-time plugin discovery / its transient plugin list) before a class is resolved, so that it knows about the highest available version. Loading early is the single most common source of "why did the old class run".

Development versions. During local development, when a dependency is checked out at dev-main or 9999999-dev, define the constant before the autoloader is required:

define( 'JETPACK_AUTOLOAD_DEV', true );
require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload_packages.php';

Otherwise semantic versioning applies and your working-copy package can lose to a released 1.x bundled by another active plugin. Never define this in production code paths.

CI integration. Because vendor/autoload_packages.php and the two vendor/composer/jetpack_autoload_*.php files are generated artifacts that encode version numbers, they must be regenerated on every release. A minimal check for a release build:

composer install --no-dev --optimize-autoloader
php -l vendor/autoload_packages.php
grep -c "'version'" vendor/composer/jetpack_autoload_classmap.php

If that grep count is zero, you have a stale or hand-edited classmap and version resolution will be wrong.

Laravel-specific integration tip. Do not add this to a Laravel application's root composer.json alongside the normal autoloader. Two Composer autoloaders on one request is exactly the conflict the package is designed to detect (JETPACK_AUTOLOAD_DEBUG_CONFLICTING_LOADERS). Keep it scoped to a WordPress plugin's own composer.json, or to a package that is only ever installed inside a WordPress plugin. If you need to share code between a Laravel app and a WP plugin, build it as a plain library and let each host bring its own autoloader.

Gotchas and Tips

Moved or renamed class files break on update. The in-memory classmap is built the moment the autoloader loads, and paths are not refreshed after a plugin update within the same request. If a plugin update relocates a class file and that file is autoloaded afterwards, you get a fatal. Practical rule: never move, rename, or re-namespace a class in the same release in which other plugins may still hold the old path. Ship the new location, wait a release cycle, then delete the old file (or keep a thin forwarding file).

Package version numbers decide hierarchy, not release dates. If a class moves into a newer package that happens to carry a lower version number (0.1.0), it will be shadowed by the older code in the 2.0.1 package. When extracting shared classes into new packages, start the new package at a version above every package that previously held those classes.

The plugin-list transient is a debugging trap. The autoloader caches the list of available plugins in a transient to avoid a filesystem scan on every request. That cache can hide early-loading bugs, making them appear intermittently — typically right after the cache is invalidated. When chasing a phantom, delete the relevant transients (or flush the object cache) and retry; a bug that only appears on a cold cache is almost always an early-load.

Two debug constants, use them deliberately. Both are booleans defined before requiring the autoloader:

define( 'JETPACK_AUTOLOAD_DEBUG_EARLY_LOADS', true );        // flags classes loaded before plugins_loaded
define( 'JETPACK_AUTOLOAD_DEBUG_CONFLICTING_LOADERS', true ); // flags stock Composer autoloaders in the stack

Leave both off in production: they add overhead and their output is not user-facing-safe.

Diagnosing "wrong version loaded". Read vendor/composer/jetpack_autoload_classmap.php in each active plugin and compare the version recorded for the same class key. If two plugins record different versions and the lower one wins, either the higher-version plugin loaded late, or it is not using this autoloader at all. Check with the conflicting-loaders constant before touching anything else.

version in composer.json matters. The autoloader reads version data to make its decision. If you build from a source checkout with no tags and no version field, Composer may record dev-* or nothing useful, and resolution becomes arbitrary. For release artifacts, always build from a tagged state.

The GitHub repo is a read-only mirror. Issue tracking and development happen in the Automattic/jetpack monorepo, and the mirror's "last release" metadata is not authoritative — the changelog runs far past it. Check the real installed version with composer show automattic/jetpack-autoloader and read the monorepo changelog before concluding a bug is unfixed. Version 5.x is current; ^2 in the README is historical.

Extension points are thin by design. There is no filter/event API. Your levers are: the two dev/debug constants, the requirement that vendor is the vendor dir, and what you put in the classmap. If you need finer control than that, the correct move is to stop using this package rather than to patch the generated files — patched classmaps will be silently overwritten on the next composer install.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robinflyhigh/livewire-datatables
rudashi/optima
misakstvanu/laravel-fortify-passkeys
insology/laravel-fatture-in-cloud
roundly-consulting/workflows-for-laravel
ipregistry/ipregistry-php
quellabs/canvas-smarty
quellabs/signal-hub
goodport/laravel-js-error-logger
szabrob/laravel-billingo
devkussema/acapapay-laravel
apartejs/laravel
smronju/nativephp-geolocation
luppakorva/laravel-nist-password-rules
owenmelbz/sashimi
gui1535/sql-to-eloquent
hashtap/laravel-responsecache
pnscripts/laravel-proverka-lite
bhawdeadlydan/laravel-accountkit
jlawrence/eos