Getting Started
A Bagisto package is a self-contained Laravel module under packages/Webkul/<Name>/src. It plugs into the same extension points as the core packages, so your feature survives Bagisto updates without an edit to core. This section builds one package, Webkul\Faq, one page at a time; this page creates it and registers it.
Package Generator
The Package Generator can scaffold this package for you. This section builds it by hand, so you see every file and how it's registered.
What You'll Build
Webkul\Faq, a store FAQ:
- a
faqstable, a model and a repository - an admin section at
/admin/faqwith a DataGrid listing, create and edit forms, a sidebar entry and ACL permissions - a storefront page at
/faq, switched on and titled from the admin configuration - English translations, ready to copy into the other 21 locales
- a listener, a console command and Pest tests
Prerequisites
- Bagisto 2.5 installed and running, with its database migrated. See Install with Composer.
- Composer and Artisan available where the application runs.
- Working knowledge of Laravel service providers, migrations, Eloquent and Blade. Architecture Overview shows where a package plugs in.
The Names Used on Every Page
| What | Name |
|---|---|
| Folder | packages/Webkul/Faq/src |
| Namespace | Webkul\Faq |
| Service providers | Webkul\Faq\Providers\FaqServiceProvider, Webkul\Faq\Providers\ModuleServiceProvider |
| Table | faqs |
| Contract, model, proxy | Webkul\Faq\Contracts\Faq, Webkul\Faq\Models\Faq, Webkul\Faq\Models\FaqProxy |
| Repository | Webkul\Faq\Repositories\FaqRepository |
| Admin routes | admin.faq.*, under /admin/faq |
| Storefront route | shop.faq.index, at /faq |
| View and translation namespace | faq:: |
| Menu and ACL key | faq |
| Configuration keys | faq.settings.general.* |
| Events | faq.create.before, faq.create.after, and the same pair for update and delete |
If you build your own package alongside, replace these names consistently, and pick a folder name no package in packages/Webkul already uses (see Things to Watch).
The Path
| Page | Adds |
|---|---|
| Getting Started (this page) | The folder, the service provider, the autoload entry and the provider registration |
| Migrations | The faqs table |
| Models | Contract, model, proxy, and the Concord module listed in config/concord.php |
| Repositories | FaqRepository and a seeder |
| Routes | The admin and storefront route files |
| Controllers | A form request, the admin controller and the storefront controller |
| Views | The admin forms and the storefront page |
| Localization | The faq:: translations |
| DataGrid | The admin listing, with row and mass actions |
| Menu | The sidebar entry, merged into menu.admin |
| Access Control List | Permissions for custom roles, merged into acl |
| System Configuration | The storefront page's settings, merged into core |
| Events, Commands and Tests | A listener, a console command and Pest tests |
The Finished Package Tree
packages/Webkul/Faq
├── src
│ ├── Config
│ │ ├── acl.php
│ │ ├── admin-menu.php
│ │ └── system.php
│ ├── Console
│ │ └── Commands
│ │ └── FaqSummary.php
│ ├── Contracts
│ │ └── Faq.php
│ ├── DataGrids
│ │ └── Admin
│ │ └── FaqDataGrid.php
│ ├── Database
│ │ ├── Migrations
│ │ │ └── <timestamp>_create_faqs_table.php
│ │ └── Seeders
│ │ └── FaqSeeder.php
│ ├── Http
│ │ ├── Controllers
│ │ │ ├── Admin
│ │ │ │ └── FaqController.php
│ │ │ └── Shop
│ │ │ └── FaqController.php
│ │ └── Requests
│ │ └── FaqRequest.php
│ ├── Listeners
│ │ └── Faq.php
│ ├── Models
│ │ ├── Faq.php
│ │ └── FaqProxy.php
│ ├── Providers
│ │ ├── EventServiceProvider.php
│ │ ├── FaqServiceProvider.php
│ │ └── ModuleServiceProvider.php
│ ├── Repositories
│ │ └── FaqRepository.php
│ ├── Resources
│ │ ├── lang
│ │ │ └── <locale>
│ │ │ └── app.php
│ │ ├── manifest.php
│ │ └── views
│ │ ├── admin
│ │ │ ├── create.blade.php
│ │ │ ├── edit.blade.php
│ │ │ ├── form-fields.blade.php
│ │ │ └── index.blade.php
│ │ └── shop
│ │ └── index.blade.php
│ └── Routes
│ ├── admin-routes.php
│ └── shop-routes.php
└── tests
├── Feature
│ └── FaqTest.php
└── FaqTestCase.phpCreate the Service Provider
The provider tells Laravel what the package contains: register() merges configuration, and boot() loads migrations, routes, views and translations. Every later page adds a line to one of the two.
File: packages/Webkul/Faq/src/Providers/FaqServiceProvider.php
<?php
namespace Webkul\Faq\Providers;
use Illuminate\Support\ServiceProvider;
class FaqServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void {}
/**
* Bootstrap services.
*/
public function boot(): void {}
}Autoload the Namespace
Add your namespace to autoload.psr-4 in the root composer.json, beside the core packages' entries:
File: composer.json
{
"autoload": {
"psr-4": {
"Webkul\\Faq\\": "packages/Webkul/Faq/src"
}
}
}The block shows only the entry to add; keep the others. Then regenerate the autoloader:
composer dump-autoloadRegister the Provider
Laravel reads service providers from bootstrap/providers.php. Import yours and add it to the end of the array:
File: bootstrap/providers.php
<?php
use App\Providers\AppServiceProvider;
use Webkul\Admin\Providers\AdminServiceProvider;
use Webkul\Faq\Providers\FaqServiceProvider;
return [
/**
* Application service providers.
*/
AppServiceProvider::class,
/**
* Webkul's service providers.
*/
AdminServiceProvider::class,
// ...
FaqServiceProvider::class,
];Test It
Clear the cached configuration first:
php artisan optimize:clearConfirm that Laravel loaded the provider. The command prints
true:bashphp artisan tinker --execute="dump(app()->providerIsLoaded(Webkul\Faq\Providers\FaqServiceProvider::class));"
Distribute or Remove a Package
Come back to this section when the package is finished.
Install It in Another Store
Give the package its own composer.json beside src, under your vendor name:
File: packages/Acme/Faq/composer.json
{
"name": "acme/faq",
"description": "A store FAQ for Bagisto.",
"autoload": {
"psr-4": {
"Acme\\Faq\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Acme\\Faq\\Providers\\FaqServiceProvider"
]
}
}
}- Composer installs it. Bagisto's root
composer.jsondeclares a path repository forpackages/*/*, so a store that has the folder runscomposer require acme/faq:@dev. The@devis needed because the root setsminimum-stabilitytostableand the folder has no tagged version. Other stores install it from Packagist or a private Composer repository. - Discovery registers the provider from
extra.laravel.providers, so the store adds neither a PSR-4 entry nor a line inbootstrap/providers.php. - The Concord module is still listed by hand in
config/concord.php, followed byphp artisan migrateandphp artisan optimize:clear. Say so in the package's README.
Remove It
Work in this order, while the package's files are still in place:
Roll back the package's tables. Given a folder,
migrate:resetrolls back only the migrations in it:bashphp artisan migrate:reset --path=packages/Webkul/Faq/src/Database/MigrationsRemove the module from
config/concord.php, the provider frombootstrap/providers.phpand theWebkul\\Faq\\entry fromcomposer.json, or runcomposer removefor a package installed through Composer.Delete the package folder, then run
composer dump-autoloadandphp artisan optimize:clear.
Settings saved under faq. keys stay in the core_config table, and custom roles keep the faq permission keys; without the package, nothing reads them.
Things to Watch
- Choose a name no package uses.
packages/Webkulalready holds the core packages,RMA,CMSandGDPRamong them, and a package that reuses one of those names writes over core files. For a package you distribute, use your own vendor name, such asAcme\Faq; this guide keepsWebkulso its paths match the rest of the documentation. - A package with models registers twice.
bootstrap/providers.phploads the service provider;config/concord.phploads theModuleServiceProviderthat registers the models. Models adds the second, and a package missing either half-loads. - Core packages aren't yours to edit. A change inside
packages/Webkul/Adminor any other core package is overwritten by the next Bagisto update. Extend it from your package: events, view render events, merged configuration, Concord model overrides, theme overrides, or a subclass bound in the container in place of a core class. - A cached configuration hides your merged entries.
mergeConfigFrom()does nothing while the configuration is cached, so runphp artisan optimize:clearafter changing a provider or aConfigfile. - A namespace missing from
composer.jsonfails as "Class not found", even when the file exists. Runcomposer dump-autoloadafter adding the entry.
Next Step
The provider loads nothing yet. The first thing the FAQ needs is its table.
Continue to: Migrations
