wm/wm-package
wm/wm-package is a Laravel/PHP package that provides reusable components, utilities, and integrations to streamline common development tasks. It is designed for clean Laravel integration, helping teams reduce boilerplate, maintain consistency, and ship features faster with less effort.
wm/wm-package is a Webmapp-authored Laravel package (webmappsrl/wm-package, MIT). The earlier "0 stars, probably a stub" read is now out of date: v1.5.0 shows this is a substantial, actively developed application-layer package for Webmapp's outdoor/mapping platform — Eloquent models (EcTrack, EcPoi, FeatureCollection), Nova resources and fields, observers, queued jobs, GeoJSON/PBF generation services, Excel import/export, and Vue components with their own Vitest suite. Treat it as a domain framework for Webmapp-shaped apps, not a generic utility.
Check the real dependency surface first. composer require wm/wm-package and then read composer.json in vendor/wm/wm-package. Based on the release, expect require entries for Laravel Nova (all those nova: commits), an Excel package (maatwebsite/excel or similar, for EcTracks/EcPois import/export), Laravel Scout (ReindexAppScoutAction), and a frontend build toolchain. Nova is a paid license — confirm your app has one before you start, or you'll install and immediately hit a wall.
Publish, then read what was published. These are your real docs:
php artisan vendor:publish --provider="Wm\WmPackage\WmPackageServiceProvider"
You're looking for: the config file (app identity, app_id, storage disk for generated GeoJSON, layer/tile settings, zoom validation bounds, slope-chart and horizontal-scroll toggles), migrations (notably the feature_collections table and geometry columns), and any Nova assets/components.
Run migrations in a dedicated PR and read the schema. FeatureCollection is new in 1.5.0 and is the centre of the release — geojson storage, relations to layers/taxonomies, observers. Confirm column types (geometry vs. json vs. longText) match what your DB engine supports.
Configure the four things that will silently break the pipeline:
GenerateFeatureCollectionJob and the order-list reordering job are async. QUEUE_CONNECTION=sync in a test env is fine; in production you need workers running.filesystems.php, not just in the package config.app_id — the new dynamic app_id filtering (with UGC fallback) means the package resolves which app's data to return. Multi-tenant installs must set this per-request/context.LayerFeatureController resolves morph types via the relation's morph map. If you use Relation::enforceMorphMap(), the package's morph aliases must be registered.First use case — the vertical slice that proves the whole thing. Pick one layer, let the observer/job generate its FeatureCollection, confirm the GeoJSON lands on your configured disk, and fetch it through the map endpoint. That single path exercises the model, the observer, the job, the service, storage, and the API controller. Alternatively, if your immediate need is data onboarding, start with the Excel import/export for EcTracks and EcPois — it's self-contained and doesn't require the full feature-collection machinery.
Follow the package's own pipeline; don't reimplement it. The 1.5.0 architecture is clear and worth respecting:
taxonomy/layer change → Observer → GenerateFeatureCollectionJob (queued)
→ FeatureCollectionService → GeometryComputationService (geometries)
→ PBFGeneratorService (tiles) → storage (geojson) → EcTrackResource / API
When you need derived map data, hook into the observer/job layer or dispatch the job yourself — never call the service synchronously inside a web request. That's exactly the pattern the package author chose, and it's the one your code should match:
GenerateFeatureCollectionJob::dispatch($featureCollection);
Use the observers as your extension point, not your enemy. layer-observer and observers "trigger regeneration on relevant changes." If your app has its own taxonomy-like models that should also invalidate a feature collection, add your own observer that dispatches the same job rather than duplicating the service call. Idempotency is the package's problem; triggering is yours.
Drive behaviour through AppConfigService + config, not forks. This release ships a lot of toggles — CAI tile config with SVG icon, horizontal scroll options, slope chart enablement, zoom-level validation rules, DEM priority logic in EcTrackResource, configurable foreign key for EcTrack::ecPois. Every one of these is a place where you can configure instead of patching. Before you write custom code to change map output, grep the config file for a key that already does it.
Nova is the admin surface — extend it, don't replace it. 1.5.0 adds ApiLinksCard, TrackColor, colour support on OrderList, FeatureCollection Nova resources, a GeoJSON export action on tracks, and improved taxonomy import/sync. For any internal tool your team needs, prefer registering the package's Nova components/fields/actions in your NovaServiceProvider over building bespoke screens. If you need a variant, subclass the field rather than editing vendor.
Import/export: use the new path, retire the old one. This release adds enhanced Excel import/export for EcTracks and EcPois and removes the legacy import command. New download options (EN/IT) are exposed via localization. Any scripts, docs, runbooks, or cron entries that call the old command must be migrated in the same deploy:
# audit before upgrading
rg "wm:|legacy|import" app/ routes/console.php config/ database/ .github/ -g '!vendor'
CSV and geometry input got a real upgrade — lean on it. CSV upload now supports point geometry, and FeatureCollectionMap handles complex and point geometries with kind detection. If your users are hand-authoring map data, the import path is now the intended workflow; don't build a bespoke importer.
Isolate what you touch behind a thin layer where it's cheap. Not everything needs wrapping now — the package is clearly first-party for Webmapp apps and you're expected to use its models and Nova resources directly. But wrap the unstable edges: anything you call that isn't in a migration or a config key. A small App\Services\FeatureCollectionGateway around job dispatch + retrieval costs ten lines and survives namespace churn.
Mirror the upstream test approach. The package integrated Vitest for the slope-chart work — meaning the frontend components have their own test harness. If you customize or wrap any Vue component, add a Vitest test of your own; PHPUnit alone won't catch a broken map component.
composer update.Bus::batch, or temporarily disable the observer. Check Horizon/queue depth after any large import — the taxonomy import/sync improvements in this release exist precisely because this is a hot path.failed() handler that logs loudly; otherwise you'll get feature collections that silently never appear.LayerFeatureController fix resolves morph types through the relation's morph map. If your app enforces a morph map, register the package's polymorphic aliases alongside yours, or layer features will 404/500 after the upgrade.app_id filtering has a UGC fallback — verify it. The dynamic app_id filter falls back to UGC (user-generated content) when no app match is found. In a multi-app install, test the empty/unknown app_id case explicitly: the fallback is a feature, but it can also mean a request leaks UGC data you didn't intend to serve.EcTrack::ecPois. Configurable means there's a default. If you have a non-standard FK column, set it in config before the upgrade deploys — a silently different default will make relations return empty rather than error."wm/wm-package": "1.5.0" (or ~1.5.0) and commit composer.lock. Then read the full v1.4.0...v1.5.0 compare — 30+ commits with Nova resources, a new model, new migrations, and a removed command is not a patch you accept blind. Deploy migrations first, then code.GenerateFeatureCollectionJob) and changed job payloads won't be picked up by long-running workers still holding old code. php artisan queue:restart belongs in your deploy script.nova:publish or the package's publish tag) and the app's frontend rebuilt. A field that "renders blank" is almost always unpushed assets, not broken PHP.zoom level validation rules means previously-accepted out-of-range zoom values in existing data may start failing validation on save or import. Audit stored min/max zoom values before upgrading if you have legacy data.FeatureCollectionMap. Re-check existing feature collections visually after upgrading — data that previously rendered as a linestring may now detect as a different kind.php artisan event:list | grep -i feature; (2) did the job run? check failed_jobs and the queue worker log; (3) did storage write? check the configured disk directly; (4) is app_id resolving correctly? (5) is the cached config stale? — php artisan config:clear. Registration → job → storage → identity → config. In that order.app/Support/Wm/ if a specific helper is wrong for you — but note the trade-off changed. In v1.4 this was the recommended path for a stub; in v1.5 the package carries real logic (PBF generation, geometry computation) that you do not want to fork. Fork small leaf classes only; keep the pipeline upstream.How can I help you explore Laravel packages today?