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

Contact Plugin Laravel Package

visiosoft/contact-plugin

A Laravel/PHP contact plugin from VisioSoft for adding contact functionality to your application. It offers a lightweight starting point for integrating contact forms and related features into Laravel or VisioSoft-based projects; refer to the package documentation for setup and usage details.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: visiosoft/contact-plugin is not a general-purpose Laravel package — it is a Streams Platform addon (the PyroCMS-derived core that powers OpenClassify). "Installing it in Laravel" means "installing it in a Streams Platform app." If your app is vanilla Laravel, budget a day to either stand up Streams Platform alongside it or reimplement the ~200 lines this addon contains yourself.

Minimal path:

composer require visiosoft/contact-plugin
php artisan addon:install visiosoft.contact
php artisan migrate

Then look, in this order:

  1. addons/default/visiosoft/contact-plugin/src/Contact/ — the Streams stream definitions. This is where the storage schema (name, email, message, timestamps) actually lives. There are no traditional Eloquent migrations to read; the "schema" is a Stream + Assignments graph.
  2. src/ContactModuleServiceProvider.php — registers the module, routes, and the admin control panel section.
  3. resources/views/ — the form partial and the admin listing. This is what you will override 90% of the time.
  4. src/Http/Controller/ — submission handling and any notification dispatch.

First use case, the 10-minute one: drop the contact form onto a page and confirm submissions land in Control Panel → Contact. In your theme template:

{% include "visiosoft.module.contact::contact/form" %}

If submissions appear in the admin but no email arrives, the problem is your MAIL_* config — not the addon (see Gotchas).

Implementation Patterns

Use the stream form builder, not hand-written HTML. The addon's value is that fields are admin-editable. Render via Streams forms so client-added fields appear automatically:

{{ form('contact').fields() }}

Hardcoding <input name="email"> will silently drop any field the client adds later.

Reading submissions in your own code. Entries are Streams entries, not plain models. Use the repository so you get the field-accessor plumbing:

use Visiosoft\ContactModule\Contact\Contract\ContactRepositoryInterface;

public function __construct(protected ContactRepositoryInterface $contacts) {}

$recent = $contacts->all();          // Collection of ContactInterface
$recent = $contacts->findBy('email', $email);

Do not ContactModel::where(...) directly unless you've checked the generated model — Streams models use a dynamic EntryModel contract and raw Eloquent scopes on custom fields will bite you.

Overriding views. Never edit the addon in addons/default/; changes vanish on composer update. Publish or override in the theme:

php artisan addon:publish visiosoft.contact
# or place files at resources/{theme}/streams/visiosoft/contact-module/...

Adding fields without code. New fields go through Admin → Streams → Contacts → Assignments. Everything downstream (form rendering, admin columns, validation from field rules) picks it up. This is the single biggest day-to-day win of the addon.

Replacing the submission flow. For anything non-trivial (CRM push, ticketing, Slack), don't fork — bind a decorator or listen for the entry-created event and handle it in your own listener:

Event::listen(\Streams\Core\Entry\Event\EntryWasSaved::class, function ($event) {
    if ($event->entry->stream()->id === 'contacts') {
        // dispatch job, notify Slack, etc.
    }
});

Notification customization. Keep mail out of the request cycle: Mail::to(...)->queue(new ContactReceived($entry)) and set QUEUE_CONNECTION to database or Redis. The addon's default sync send will hang your form on a slow SMTP host.

Testing. Fake mail and isolate the stream:

Mail::fake();
$this->post(route('visiosoft.module.contact::contact.create'), [
    'name' => 'A', 'email' => '[email protected]', 'message' => 'hi',
])->assertRedirect();
Mail::assertQueued(ContactReceived::class);

Wrap in RefreshDatabase — Streams migrations create real tables (data_contact_contacts style) and transaction rollback of stream writes is unreliable.

Gotchas and Tips

  • Version pinning is mandatory. Last release is May 2022, 0 dependents. Pin "visiosoft/contact-plugin": "~1.0" and commit composer.lock; an unpinned transitive Streams bump will break field assignment silently.
  • Stream schema lives in the DB, not in code. Adding a field via admin creates columns/assignments at runtime. After a migrate:fresh on a dev box you get a different schema than production. Always replay from a known snapshot before assuming a bug.
  • Cache clears are not optional. Streams caches the compiled schema aggressively. After changing assignments or views: php artisan cache:clear, then php artisan streams:compile if you have it, and clear the theme's compiled views. "My new field doesn't show" is almost always this.
  • No spam protection ships with it. Expect bot submissions within days. Add a honeypot field plus rate limiting in middleware — do not bolt a g-recaptcha into an overridden addon view, use your own controller action so it survives updates.
  • Email failures look like plugin failures. Check storage/logs/laravel.log and MAIL_MAILER=log before touching addon code. Also confirm the recipient address — control-panel notification settings override .env.
  • View override path must match exactly. Namespace is visiosoft.module.contact::…; a stray .blade.php extension or a contact-module vs contact-plugin mixup in the override directory means your file is silently ignored with zero errors.
  • Don't hand-edit stream tables. Field columns and data_* tables are managed by the Streams migrator. Manual ALTER TABLE is reverted on the next compile and can corrupt the assignment cache.
  • Permissions and multi-site. New control-panel sections need role permissions granted explicitly; and if the app is multi-site, entries are scoped by site — a query that "loses" records is usually a missing site scope.
  • Debugging toolkit: Laravel Telescope + MAIL_MAILER=log gets you through 95% of "form doesn't work" reports. If a submission 500s, look at EntryModel save — validation rules defined in the field assignments are the usual culprit (a required field added by the client, not present in their form).
  • Extension points, in order of preference: Streams field assignments → event listeners on entry save → decorator binding on ContactRepositoryInterface → view override → fork. Forking is the last resort, but given the package's age and zero dependents, treat the source as reference implementation you can own rather than a dependency you can rely on upstream to maintain.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource