Welcome to WhatsmarkSaaS custom module development! This comprehensive guide will walk you through creating powerful, maintainable modules that extend your WhatsmarkSaaS platform with custom functionality.
What You'll Learn
By the end of this guide, you'll be able to:
Set up a complete custom module structure
Implement proper service providers and configuration
Create routes, controllers, and views
Handle database migrations and models
Implement security best practices
Test your module effectively
Before starting custom module development, ensure you have:
Requirements Checklist
WhatsmarkSaaS Platform: Version 2.0 or higher installed and running
PHP Knowledge: Familiarity with PHP 8.3 and Laravel 12+
Development Environment: Local development setup with database access
WhatsmarkSaaS modules follow a structured architecture that ensures maintainability and compatibility:
Modules/YourModule/
├── Config/
│ └── config.php
├── Database/
│ ├── Migrations/
│ └── Seeders/
├── Http/
│ ├── Controllers/
│ ├── Middleware/
│ └── Requests/
├── Providers/
│ └── YourModuleServiceProvider.php
├── Resources/
│ ├── assets/
│ ├── lang/
│ └── views/
├── Routes/
│ ├── web.php
│ └── api.php
├── Tests/
├── composer.json
└── module.jsonUse the built-in module generator to create your module skeleton:
Using Artisan CommandManual Creation
php artisan module:make YourModuleNameEdit the module.json file to define your module's metadata:
{
"name": "YourModule",
"alias": "yourmodule",
"description": "Your module description",
"keywords": ["whatsmarksaas", "module", "your-feature"],
"version": "1.0.0",
"active": 1,
"order": 1,
"providers": [
"Modules\\YourModule\\Providers\\YourModuleServiceProvider"
],
"files": []
}Create your module's service provider in Providers/YourModuleServiceProvider.php:
<?php
namespace Modules\YourModule\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Factory;
class YourModuleServiceProvider extends ServiceProvider
{
protected string $moduleName = 'YourModule';
protected string $moduleNameLower = 'yourmodule';
public function boot(): void
{
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
}
public function register(): void
{
$this->app->register(RouteServiceProvider::class);
// Register module config
$this->mergeConfigFrom(
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
);
}
protected function registerConfig(): void
{
$this->publishes([
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
], 'config');
}
protected function registerViews(): void
{
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'Resources/views');
$this->publishes([
$sourcePath => $viewPath
], ['views', $this->moduleNameLower . '-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
}
protected function registerTranslations(): void
{
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'Resources/lang'));
}
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (config('view.paths') as $path) {
if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
$paths[] = $path . '/modules/' . $this->moduleNameLower;
}
}
return $paths;
}
}Create Routes/web.php for your module's web routes. This file should contain:
Admin routes with proper middleware
User-facing routes
Protected routes with authentication
Create Routes/api.php for API endpoints including:
Public API endpoints
Protected API routes with authentication
Webhook endpoints (remember to exclude from CSRF)
Create controllers in Http/Controllers/ directory:
AdminController: Handle admin functionality
UserController: Handle user-facing features
ApiController: Handle API requests and webhooks
Ensure controllers follow Laravel conventions and keep them slim by moving business logic to service classes.
Generate migrations for your module:
php artisan module:make-migration create_yourmodule_table YourModuleDesign your database schema considering:
Proper foreign key relationships
Appropriate indexes for performance
Nullable fields where needed
JSON columns for flexible data storage
Create Eloquent models in the Models/ directory:
Define fillable attributes
Set up model relationships
Add custom scopes and accessors
Implement proper data casting
Create Blade templates in Resources/views/:
Admin views: Dashboard, settings, management interfaces
User views: User-facing interfaces
Layouts: Extend existing layouts or create module-specific ones
Ensure views follow your application's design system and accessibility standards.
Create Config/config.php with your module settings:
Module metadata (name, version)
Feature flags for optional functionality
Default configuration values
Environment-specific settings
For webhook endpoints, add CSRF exclusions in your service provider. See the CSRF Token Validation guide for detailed implementation.
Create custom middleware in Http/Middleware/ for:
Module-specific access control
Feature availability checks
Request validation and transformation
Security logging
Create comprehensive tests in the Tests/ directory:
Feature Tests: Test complete user workflows
Unit Tests: Test individual classes and methods
API Tests: Test API endpoints and responses
Security Tests: Verify access controls and validation
# Activate the module
php artisan module:enable YourModule
# Run migrations
php artisan migrate
# Publish assets (if any)
php artisan module:publish YourModule# Check module status
php artisan module:list
# Test module routes
php artisan route:list | grep yourmodule