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

Core Project Message Laravel Package

drupal/core-project-message

A small Composer plugin used by Drupal project templates to display a helpful post-install message. After Composer creates a Drupal project, it surfaces next steps, documentation links, and setup guidance directly in the console, making it easier for new users to get started.

Deep Wiki
Context7

Getting Started

drupal/core-project-message is a tiny Composer plugin (type composer-plugin) that subscribes to Composer's post-create-project-cmd event and prints whatever lines you configured in the root composer.json. It does no installation work itself — it is a declarative "welcome banner" hook. It ships as part of Drupal's recommended-project/legacy-project templates, but the mechanism is framework-agnostic and works for any composer create-project flow you control.

Install

composer require drupal/core-project-message

Put it in require (not require-dev) of the template package you intend to create-project, because create-project installs the template's runtime requirements before the event fires.

Allow the plugin (Composer ≥ 2.2)

composer config allow-plugins.drupal/core-project-message true

Or commit it in composer.json:

"config": {
    "allow-plugins": {
        "drupal/core-project-message": true
    }
}

Where to look first

  1. The root extra.drupal-core-project-message.post-create-project-cmd-message array — this is the entire public API surface.
  2. vendor/drupal/core-project-message/src/Plugin.php (namespace Drupal\CoreProjectMessage) — ~40 lines; read it before assuming behavior.
  3. The package's own composer.json for the extra.class autoload wiring.

First use case — brand the first-run output of your company starter kit:

"extra": {
    "drupal-core-project-message": {
        "post-create-project-cmd-message": [
            "<bg=green;fg=black> Acme Site installed </>",
            "",
            "Next steps:",
            "  1. cp .env.example .env",
            "  2. composer run dev",
            "  Docs: https://internal.acme/site-template"
        ]
    }
}

Then composer create-project acme/site-template ./my-site prints it once, right after the scaffold and post-create-project-cmd scripts complete.

Implementation Patterns

Declarative banner in the template. Each array entry becomes one output line. Keep it to onboarding instructions that are only true at creation time — credentials to set, the dev server command, where to file issues. Do not put anything that must be revisited later.

White-labeling a reusable starter kit. Since the message is read from the installed root package's extra, the same template can be re-badged by forking and editing only composer.json. No PHP changes, no plugin fork.

Symfony Console styling. The strings are passed to Composer's IO, so <bg=blue;fg=white>…</>, <info>, <comment>, <error>, and <href=…> all work. Style block-level banners with full-width padding so they render as a solid bar:

"<bg=blue;fg=white>                                          </>",
"<bg=blue;fg=white>  Congratulations, your site is installed  </>",
"<bg=blue;fg=white>                                          </>"

Separate "print" from "do". This plugin only prints. Any real first-run work (generating keys, copying .env, seeding a DB) belongs in scripts.post-create-project-cmd in the same composer.json; the two run in the same phase, so the banner and the actions feel like one onboarding step.

"scripts": {
    "post-create-project-cmd": [
        "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
        "@php artisan key:generate --ansi"
    ]
}

Reusing the pattern outside Drupal. If you want messages on post-install-cmd/post-update-cmd too, this package will not do it — copy Plugin.php into a private composer-plugin package and add the extra event keys to getSubscribedEvents(). That is roughly a 20-line fork and is the intended extension point.

Local test loop. Point a path repository at your template and run create-project into a throwaway directory:

composer create-project acme/site-template /tmp/site-test \
  --repository='{"type":"path","url":"../site-template","options":{"symlink":false}}'

Delete /tmp/site-test between runs; the event only fires on a genuinely new project directory.

CI integration. For smoke tests, assert on the output with --no-ansi so the formatter tags become plain text and greppable:

composer create-project acme/site-template /tmp/ci --no-ansi | grep -q "Next steps"

Gotchas and Tips

  • Silently inert without allow-plugins. On Composer ≥ 2.2 an unallowed plugin is skipped with only a warning during install, so the banner never appears and there is no error at create-project time. In non-interactive CI, set it via composer config allow-plugins... true before running.
  • post-create-project-cmd only. Editing the message array in an existing checkout does nothing — install and update never dispatch this event. Do not use it for upgrade notices; use a post-update-cmd script or your own plugin.
  • --no-install and --no-scripts kill it. composer create-project --no-install skips the install phase entirely, so the listener never runs. Verify your onboarding docs don't recommend flags that suppress it.
  • Typos fail silently. If the extra key is misspelled or the value is not an array, the plugin finds nothing and prints nothing — no exception, no warning. When a banner "disappears," diff the key name first.
  • Formatter tags are not HTML. Symfony Console's OutputFormatter only understands its own tag grammar; unknown tags typically pass through literally, and text containing < or > (e.g. <[email protected]>) can be swallowed or mangled. Escape or rephrase angle-bracket content.
  • Ordering relative to your scripts. Both the plugin listener and the root package's post-create-project-cmd scripts fire for the same event; do not assume the banner prints before or after your .env generation. If sequencing matters, keep the banner purely informational.
  • Output destination. Messages go to Composer's normal stdout and are suppressed by --quiet. They show up in CI logs and shell history captures — never put tokens, one-time passwords, or internal hostnames you would not commit to a repo.
  • Version coupling. The package versions in lockstep with Drupal core branches; pin a constraint compatible with your Composer plugin API (composer-plugin-api) and re-test after major Composer upgrades, since event names and IO behavior are Composer's to change.
  • License. GPL-2.0 — fine inside a Drupal project, but check before copying Plugin.php into a proprietary product; reimplementing the idea (it is trivially small) is usually cheaper than a license review.
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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log