### Running ModulesPress Docs - Bash Source: https://github.com/devsroutes/modulespress-docs/blob/master/README.md These commands provide the quick start guide to set up and run the documentation project locally. `npm install` fetches necessary dependencies, `npm start` launches a local development server for live preview, and `npm run build` compiles the project for production deployment. ```bash # Install dependencies npm install # Start development server npm start # Build for production npm run build ``` -------------------------------- ### Create New ModulesPress Plugin Project (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/02-installation.md Executes the ModulesPress CLI command to initiate the creation of a new plugin project. The command guides the user through configuration prompts and automatically sets up the project directory, dependencies, and initial files. ```bash modulespress new ``` -------------------------------- ### Install ModulesPress CLI via Composer (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/02-installation.md Installs the ModulesPress command-line interface tool globally using Composer. This tool is a prerequisite for creating and managing ModulesPress plugin projects easily. ```bash composer global require modulespress\/cli ``` -------------------------------- ### Example Generated ModulesPress Controller (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet shows an example of a controller class generated by the ModulesPress CLI. It includes `#[Injectable]` and `#[RestController]` attributes and provides boilerplate methods for GET and POST requests with parameter and body handling. ```php #[Injectable] #[RestController("/namespace")] class ControllerName { #[Get(':id')] public function get(#[Param('id')] string $id): array {} #[Post] public function create(#[Body] array $body): array {} } ``` -------------------------------- ### Installing ModulesPress CLI using Composer (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md Installs the ModulesPress CLI tool globally on your system using Composer. This command requires Composer to be installed and accessible. After installation, you might need to add Composer's global bin directory to your system's PATH. ```bash composer global require modulespress/cli ``` -------------------------------- ### GitHub Actions Workflow for Packaging (YAML) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/08-packaging.md This YAML configuration defines an example GitHub Actions workflow. It's triggered upon the creation of a new release, checks out the code, installs both PHP (Composer) and Node.js (npm) dependencies, builds frontend assets, and finally runs the `modulespress pack` command to create the release artifact. ```YAML name: Package Plugin on: release: types: [created] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Dependencies run: | composer install npm install - name: Build Assets run: npm run build - name: Package Plugin run: modulespress pack ``` -------------------------------- ### Advanced Plugin Configuration Example PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/05-plugin-configuration.md Presents a comprehensive example of an `AdvancedPlugin` class extending `ModulesPressPlugin`, demonstrating constant definitions for name, slug, and prefix, setting version and REST namespace properties, configuring the environment in the constructor, and overriding the `onPluginReady` method for advanced initialization logic. It concludes with bootstrapping the plugin instance. ```php final class AdvancedPlugin extends ModulesPressPlugin { public const NAME = "Advanced ModulesPress Plugin"; public const SLUG = "advanced-modulespress"; public const PREFIX = "amp_"; protected string $version = "1.2.0"; protected string $restNamespace = "advanced-plugin/v1"; public function __construct() { $this->configureEnvironmentSettings(); parent::__construct( rootModule: AdvancedRootModule::class, rootDir: __DIR__, rootFile: __FILE__ ); } // Implement custom lifecycle methods protected function onPluginReady(ModulesPressPlugin $plugin): void { // Advanced initialization logic } } (new AdvancedPlugin())->bootstrap() ``` -------------------------------- ### Example Generated ModulesPress Service Provider (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet provides an example of a service provider class generated by the ModulesPress CLI. It includes the `#[Injectable]` attribute, marking it for dependency injection, and a basic constructor. ```php #[Injectable] class ProviderName { public function __construct() {} } ``` -------------------------------- ### Example Generated ModulesPress Guard (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet provides an example of a guard class structure. It implements the `CanActivate` interface and includes the required `canActivate` method signature, which returns a boolean indicating whether the request should proceed based on the execution context. ```php class GuardName implements CanActivate { public function canActivate(ExecutionContext $context): bool {} } ``` -------------------------------- ### CPT Repository Design Best Practice Example PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/04-entities-and-repository/02-cpt-repositories.md Provides an example illustrating the best practice of using specific, descriptive method names (`findPublishedInSeries`) for repository queries instead of generic methods (`findCustom`) that require complex argument arrays. ```php class BookRepository extends CPTRepository { // ✅ Good: Specific, meaningful method names public function findPublishedInSeries(string $series): array // ❌ Bad: Generic, unclear methods public function findCustom(array $args): array } ``` -------------------------------- ### ViewCompose Admin Menu Example PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/05-renderer.md An example demonstrating how to use the #[ViewCompose] attribute to inject multiple pieces of data (books, categories, last updated time) into the 'network-admin-menu' Blade view before it is rendered. ```php #[ViewCompose('network-admin-menu')] public function composeAdminMenu(BladeOne $view) { $view->with([ 'books' => $this->bookRepository->getAllBooks(), 'categories' => $this->categoryService->getCategories(), 'lastUpdated' => current_time('mysql') ]); } ``` -------------------------------- ### ViewCompose Main Layout Example PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/05-renderer.md Example showing how to use #[ViewCompose] to inject common data like site name, current user, and notifications into a main layout view ('layouts.main'), ensuring this data is available across all pages using this layout. ```php #[ViewCompose('layouts.main') safeguard required public function composeMainLayout(BladeOne $view) { $view->with([ 'siteName' => get_bloginfo('name'), 'currentUser' => wp_get_current_user(), 'notifications' => $this->notificationService->getAll() ]); } ``` -------------------------------- ### Creating New ModulesPress Plugin (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md Generates a new ModulesPress plugin boilerplate with the basic structure, necessary configuration files, and default setup. The command takes the desired name for the new plugin as an argument. ```bash modulespress new plugin-name ``` -------------------------------- ### Basic ModulesPress REST Controller in PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/01-controllers.md Demonstrates the fundamental structure of a ModulesPress controller using `#[RestController]` for namespace definition. Shows dependency injection via the constructor with `#[Inject]` and defines basic GET and POST endpoints using `#[Get]` and `#[Post]` attributes, including `#[Body]` for request payload. ```php #[RestController(namespace: "/books")] class BooksController { public function __construct( #[Inject("bookService")] private readonly BooksServiceProvider $booksService ) {} #[Get] public function getBooks(): array { return $this->booksService->getBooks(); } #[Post] public function createBook( #[Body] CreateBookDTO $book ): array { return [ "message" => "Book created", "book" => $book ]; } } ``` -------------------------------- ### Running Vite Development Server Bash Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Provides the command-line instruction to start the Vite development server. This server is crucial during development for features like Hot Module Replacement (HMR) and resolving assets directly from the source files. ```bash npm run dev ``` -------------------------------- ### Injecting WordPress Options using Providers (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/02-providers.md Provides a practical example demonstrating how to fetch WordPress options using `get_option` within a static factory method and make them available for injection (as 'Options') into a service (`WordPressSettingsService`) via a Provider configuration. ```php #[Injectable] class WordPressSettingsService { public function __construct( #[Inject("Options")] private array $pluginOptions ) {} public function getSettingsPageTheme() { return $this->pluginOptions["themeColor"]; } } #[Module( providers: [ WordPressSettingsService::class, new Provider( provide: "Options", useFactory: [WordPressIntegrationModule::class, "pluginOptions"] ) ] )] class WordPressIntegrationModule extends ModulesPressModule { public static function pluginOptions() { $options = array(); $options["themeColor"] = get_option("themeColor"); return $options; } } ``` -------------------------------- ### Bootstrapping - ModulesPress Plugin - PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/01-introduction.md This PHP snippet shows the basic structure of the main plugin file for a ModulesPress plugin. It defines a final class that extends `ModulesPressPlugin`, initializes the parent constructor with the root module, directory, and file, and then calls the `bootstrap` method to start the framework. This file serves as the core entry point for the plugin. ```php bootstrap(); ?> ``` -------------------------------- ### Running Vite Development Server for ModulesPress Assets Bash Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Provides a command to start the Vite development server, which is often required for assets (like those bundled by Vite) to load correctly during the development phase in a ModulesPress project. ```bash # Ensure Vite server is running npm run dev ``` -------------------------------- ### Creating Custom ModulesPress Exception Class in PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Provides an example of creating a custom exception class (`BookNotFoundException`) that extends a base exception (`BaseException` or `NotFoundHttpException`). It defines a constructor to accept message, code, reason, and previous exception parameters for consistency. ```php class BookNotFoundException extends BaseException // or consider extending NotFoundHttpException instead { public function __construct( string $message = "Book not found", int $code = 404, string $reason = "", ?\Throwable $previous = null ) { parent::__construct($message, $code, $reason, $previous); } } ``` -------------------------------- ### Customizing ModulesPress Production HTML Error Template in Blade Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Provides a more complete example of the `generic.blade.php` template, demonstrating how to extend a layout (`layouts.error`), include localization (`__('...')`), and add custom content and actions like a 'Return Home' button. ```blade {{-- views/errors/generic.blade.php --}} @extends('layouts.error') @section('content')

{{ __('Oops! Something went wrong') }}

{{ $exception->getMessage() }}

{{-- Add custom content --}}
{{ __('Return Home') }}
@endsection ``` -------------------------------- ### ModulesPress Basic Production HTML Error Template in Blade Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Shows a basic example of the `generic.blade.php` template used by ModulesPress to render HTML error pages in the production environment (when debug mode is off). It displays the exception code and message. ```blade
{{ $exception->getCode() }}

{{ $exception->getMessage() }}

``` -------------------------------- ### Implementing Rate Limiting Middleware PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/03-middleware.md This snippet provides an example of a class-based middleware for rate limiting. It gets the client's IP address, checks if the rate limit is exceeded using a dependency (`$this->rateLimiter`), and returns a 429 Too Many Requests response if exceeded, or allows processing to continue otherwise. ```php class RateLimitMiddleware implements Middleware { public function use(WP_REST_Request $req, WP_REST_Response $res): WP_REST_Request|WP_REST_Response { $clientIp = $req->get_remote_addr(); if ($this->rateLimiter->isLimitExceeded($clientIp)) { $res->set_status(429); $res->set_data([ 'error' => 'Rate limit exceeded', 'retry_after' => $this->rateLimiter->getRetryDelay() ]); return $res; // Immediately return error response } return $req; // Continue processing } } ``` -------------------------------- ### Specifying Exception Reason for Debugging in PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Demonstrates how to include a detailed debugging `reason` when throwing an exception (e.g., `BadRequestHttpException`) by using the named `reason` parameter in the constructor. This reason is intended for debugging and not for end-users. ```php // Basic usage throw new BadRequestHttpException( "Invalid input provided", reason: "Expected numeric ID, received string 'abc123'" ); // ❌ Bad throw new BadRequestHttpException( "Database error: Unable to connect to MySQL on 192.168.1.100" ); // ✅ Good throw new BadRequestHttpException( "Unable to process request", reason: "Database connection failed: MySQL connection refused on 192.168.1.100" ); ``` -------------------------------- ### Example Generated ModulesPress Taxonomy (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet illustrates the basic structure of a taxonomy class generated by the ModulesPress CLI. It utilizes the `#[Taxonomy]` attribute to define the taxonomy's slug, singular, and plural names. ```php #[Taxonomy( slug: 'taxonomy', singular: 'Name', plural: 'Names' )] class TaxonomyName ``` -------------------------------- ### Accessing Built-in Directory Paths PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/05-plugin-configuration.md Provides examples of using built-in methods available on the `ModulesPressPlugin` instance to retrieve important plugin directory paths and URLs. These methods include `getRootDirPath()`, `getRootDirUrl()`, `getViewsDirPath()`, and `getCacheDirPath()`. ```php // Retrieve various plugin directory paths $rootDir = $plugin->getRootDirPath(); // Plugin root directory $rootUrl = $plugin->getRootDirUrl(); // Plugin root URL $viewsDir = $plugin->getViewsDirPath(); // Views directory $cacheDir = $plugin->getCacheDirPath(); // Cache directory ``` -------------------------------- ### Extending Core Exception Filter for Custom Handling (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Shows how to extend the `CoreExceptionFilter` to override specific context handling methods, such as `forRestResponse`. This example demonstrates catching `BadRequestException` and `ValidationException` specifically, providing custom data in the REST response while relying on the parent class for other exceptions and contexts. ```PHP #[Injectable] #[CatchException(BadRequestException::class, ValidationException::class)] class CustomExceptionFilter extends CoreExceptionFilter { public function __construct( // Automatically resolves private readonly Renderer $renderer, private readonly ModulesPressPlugin $plugin ) { parent::__construct($this->renderer, $this->plugin->isDebugMode()); // Required } protected function forRestResponse( BaseException $exception, ExecutionContext $executionContext ): WP_REST_Response { $response = $executionContext->switchToRESTContext()->getWPResponse(); $response->set_data([ 'customField' => 'Custom handling', 'message' => $exception->getMessage(), 'code' => $exception->getCode() ]); return $response; } } ``` -------------------------------- ### Example Generated ModulesPress Middleware (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet shows a generated middleware class structure. It implements the `Middleware` interface and includes the required `use` method signature for interacting with `WP_REST_Request` and `WP_REST_Response` objects during request processing. ```php class MiddlewareName implements Middleware { public function use(WP_REST_Request $req, WP_REST_Response $res): WP_REST_Request|WP_REST_Response {} } ``` -------------------------------- ### Admin Dashboard Asset Enqueuing PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md A comprehensive real-world example demonstrating the enqueuing of assets for an admin dashboard page. It shows how to enqueue an application, specify dependencies, localize complex configuration data, inject the static path resolver, and enqueue additional standalone scripts and styles. ```php #[UseChecks([new IsAdminMenuCheck(self::ADMIN_MENU_PAGE_SLUG)])] #[Add_Action('admin_enqueue_scripts')] public function enqueueAdminAssets(): void { // Enqueue main dashboard application $app = $this->enquerer->app('admin/dashboard/app.tsx') ->dependencies(['wp-components', 'wp-api-fetch']) ->enqueue() ->withStyles(); // Add configuration and utilities $app->localize('dashboardConfig', [ 'restBase' => rest_url('modulespress/v1'), 'nonce' => wp_create_nonce('wp_rest'), 'user' => wp_get_current_user(), 'permissions' => [ 'canManageOptions' => current_user_can('manage_options'), 'canEditPosts' => current_user_can('edit_posts') ] ]); // Add static path resolver $app->inline($this->enquerer->injectStaticPathResolver()); // Add utility scripts or import directly in app files using `import` $this->enquerer->script('admin/utils/analytics.ts') ->enqueue(); // Add additional styles or import directly in app files using `import` $this->enquerer->style('admin/styles/dashboard.scss') ->enqueue(); } ``` -------------------------------- ### Enqueuing Style Assets with Options PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Provides examples for enqueuing `StyleAsset` instances. It covers simple enqueuing of an SCSS file, enqueuing with a specific media query using `media()`, and adding inline CSS directly to the style tag using `inline()`. These methods offer flexibility in how styles are applied. ```php // Basic SCSS enqueuing $this->enquerer->style('admin/styles/main.scss') ->enqueue(); // With media queries and conditions $this->enquerer->style('frontend/responsive.scss') ->enqueue() ->media('screen and (min-width: 768px)'); // With inline styles $this->enquerer->style('components/modal.scss') ->enqueue() ->inline('.modal { display: none; }'); ``` -------------------------------- ### Organizing Feature Components in a Module - ModulesPress - PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/01-modules.md Shows how ModulesPress modules can be used to group related feature components, such as controllers and services. This example defines a `CatsController`, a `CatsService`, and a `CatsModule` that registers these components. ```php // CatsController.php class CatsController { // Cats-specific controller logic } ``` ```php // CatsService.php class CatsService { // Cats-related business logic } ``` ```php // CatsModule.php #[Module( providers: [ CatsService::class ], controllers: [ CatsController::class ] )] class CatsModule extends ModulesPressModule {} ``` -------------------------------- ### Frontend Widget Asset Enqueuing PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md A real-world example for enqueuing assets for a frontend widget. It demonstrates conditional enqueuing based on the current page (`is_single()`), enqueuing a frontend application, localizing widget configuration, and enqueuing a style asset with a media query for responsiveness. ```php #[Add_Action('wp_enqueue_scripts')] public function enqueueFrontendAssets(): void { if (!is_single()) { return; }s // Enqueue widget application $widget = $this->enquerer->app('frontend/widget/app.tsx') ->dependencies(['wp-element']) ->enqueue() ->withStyles(); // Configure widget $widget->localize('widgetConfig', [ 'postId' => get_the_ID(), 'apiEndpoint' => rest_url('modulespress/v1/widget'), 'theme' => get_option('widget_theme', 'light') ]); // Add responsive styles $this->enquerer->style('frontend/styles/widget-responsive.scss') ->enqueue() ->media('screen and (max-width: 768px)'); } ``` -------------------------------- ### Configuring Dependency Scopes with ModulesPress Providers (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/02-providers.md Illustrates how to specify the lifecycle scope for provided dependencies using the `scope` property in the `Provider` configuration. It shows examples for `Scope::SINGLETON` (one instance per request) and `Scope::TRANSIENT` (new instance per injection). ```php #[Module( providers: [ // Singleton: Same instance throughout the request lifecycle new Provider( provide: UserRepository::class, useClass: UserRepository::class, scope: Scope::SINGLETON ), // Transient: New instance on every injection new Provider( provide: LoggerService::class, useClass: LoggerService::class, scope: Scope::TRANSIENT ) ] )] class CoreModule extends ModulesPressModule {} ``` -------------------------------- ### Example Generated ModulesPress CPT Entity (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet shows the basic structure of a Custom Post Type entity class generated by the ModulesPress CLI. It includes the `#[CustomPostType]` attribute for configuration and extends the base `CPTEntity` class. ```php #[CustomPostType( name: 'cpt_name', singular: 'Name', plural: 'Names' )] class EntityName extends CPTEntity ``` -------------------------------- ### Example Generated ModulesPress Pipe (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet illustrates a generated pipe class structure. It implements the `PipeTransform` interface and provides the required `transform` method signature, which takes an input value and returns a potentially modified value. ```php class PipeName implements PipeTransform { public function transform(mixed $value): mixed {} } ``` -------------------------------- ### Enqueuing Script Asset with Options PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Demonstrates the fluent API for enqueuing a `ScriptAsset`. This example shows how to specify dependencies (`dependencies()`), enqueue the script (`enqueue()`), localize data to make PHP variables available in JavaScript (`localize()`), add inline scripts (`inline()`), explicitly mark it as a module (`module()`), and retrieve the asset's version (`getVersion()`). ```php // Enqueue a TypeScript file with dependencies and localization $this->enquerer->script('admin/dashboard.ts') ->dependencies(['jquery', 'wp-api']) ->enqueue() ->localize('dashboardData', [ 'apiUrl' => rest_url(), 'nonce' => wp_create_nonce('wp_rest') ]) ->inline("window.DASHBOARD_VERSION = '1.0.0'"); $version = $this->enquerer->script('utils/helper.ts') ->handle('helper') ->enqueue() ->module() //explicetly mark as module, enquerer take care of it by default ->getVersion(); // return version of this asset ``` -------------------------------- ### Applying Interceptor to Method ModulesPress PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/05-interceptors.md Demonstrates applying the `CacheInterceptor` to the `getFeaturedProducts` method of `ProductsController` using the `#[UseInterceptors]` attribute. This provides fine-grained control over which methods are intercepted. It also shows the `@Get` attribute for routing. ```php class ProductsController { #[UseInterceptors(CacheInterceptor::class)] #[Get("featured")] public function getFeaturedProducts(): array { return $this->productService->getFeatured(); } } ``` -------------------------------- ### Registering Global Exception Filter (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Demonstrates how to register an exception filter that applies globally to the entire plugin. This is achieved by returning an array of filter class names from the `pluginFilters` method within a class that extends `ModulesPressModule`. ```PHP class YourModule extends ModulesPressModule { public function pluginFilters(): array { return [ GlobalExceptionFilter::class ]; } } ``` -------------------------------- ### Configuring Providers in ModulesPress Module (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/02-providers.md Shows how to define various types of providers within a `#[Module]` attribute's `providers` array, including class-based, named service (`useClass`), static value (`useValue`), and factory-based (`useFactory`) providers. Includes an example factory method. ```php #[Module( providers: [ // Class-based provider UserRepository::class, // Named service provider new Provider( provide: "notificationService", useClass: EmailNotificationService::class ), // Static value provider new Provider( provide: "emailApiKey", useValue: "your-api-key-here" ), // Factory-based provider new Provider( provide: "configManager", useFactory: [ConfigurationModule::class, "createConfigManager"] ) ] )] class UserModule extends ModulesPressModule { // Factory method example public static function createConfigManager() { return new ConfigManager( environment: wp_get_environment_type(), basePath: WP_CONTENT_DIR ); } } ``` -------------------------------- ### Example Generated ModulesPress Interceptor (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet shows a generated interceptor class structure. It implements the `Interceptor` interface and includes the required `intercept` method signature for executing logic before or after a method call within the execution context. ```php class InterceptorName implements Interceptor { public function intercept(ExecutionContext $context, CallHandler $next): mixed {} } ``` -------------------------------- ### Defining Plugin Version in Header (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/08-packaging.md This example shows the standard WordPress plugin header structure in the main plugin file. The `Version` field is critical because the ModulesPress `pack` command reads this value to name the generated production package ZIP file. ```PHP /** * Plugin Name: Books Generator * Description: Generate books for your WordPress site. * Version: 1.0.0 * Author: Your Name * License: GPL2 * Text Domain: books-generator */ ``` -------------------------------- ### Full ModulesPress Service Provider for WordPress Hooks - PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/03-wordpress-hooks.md Presents a complete example of a Service Provider class utilizing ModulesPress attributes (`#[Add_Action]`, `#[Add_Filter]`) to manage various WordPress hooks. It demonstrates organizing different hook registrations within a single class for initialization, admin menus, and content modification, showcasing a structured approach. ```php namespace BookPlugin\Provider; use ModulesPress\Foundation\Hookable\Attributes\Add_Action; use ModulesPress\Foundation\Hookable\Attributes\Add_Filter; class BookServiceProvider { #[Add_Action('init', priority: 5)] public function initializeBookSystem() { // Initialize book-related systems } #[Add_Action('admin_menu')] public function registerAdminPages() { // Register admin menu items } #[Add_Filter('the_content', priority: 10)] public function enhanceBookContent($content) { // Modify content display return $content; } } ``` -------------------------------- ### Utilizing Built-in CPT Repository CRUD Operations PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/04-entities-and-repository/02-cpt-repositories.md Provides examples of using the standard CRUD methods available on a CPT Repository instance, including finding by ID, finding all, finding by criteria, saving (create/update), and removing an entity. ```php class BookController { public function __construct( private BookRepository $repository ) {} public function examples() { // Find by ID $book = $this->repository->find(123); // Find all $allBooks = $this->repository->findAll(); // Find by criteria $books = $this->repository->findBy([ 'post_status' => 'publish', 'orderby' => 'title' ]); // Save (create or update) $book = new Book(); $book->title = 'New Book'; $this->repository->save($book); // Remove $this->repository->remove($book); } } ``` -------------------------------- ### Optimizing Composer Autoloader (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/08-packaging.md This Composer command is used within the packaging process to ensure only production dependencies are installed (`--no-dev`) and the Composer autoloader is optimized (`--optimize-autoloader`). This results in a smaller package size and faster autoloading. ```Bash composer install --no-dev --optimize-autoloader ``` -------------------------------- ### Implementing a Custom JWT Authentication Guard in ModulesPress (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/04-guards.md Provides an example of a guard (`JwtGuard`) for verifying JSON Web Tokens. It demonstrates accessing the 'Authorization' header from the request context and using a hypothetical JWT library to decode and validate the token, returning `true` only if the token is valid. ```PHP #[Injectable] class JwtGuard implements CanActivate { public function canActivate(ExecutionContext $ctx): bool { $request = $ctx->switchToRESTContext()->getWPRequest(); $token = $request->get_header('Authorization'); if (!$token) { return false; } try { // Verify JWT token (using your preferred JWT library) $decoded = JWT::decode($token, new Key(YOUR_SECRET_KEY, 'HS256')); return true; } catch (Exception $e) { return false; } } } ``` -------------------------------- ### Implementing Blog Switch Interceptor WordPress PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/05-interceptors.md Designed for WordPress multisite installations, this interceptor reads the 'Blog-Id' header to switch the global blog context using `switch_to_blog` before handler execution and `restore_current_blog` afterward. It ensures database operations target the correct blog and throws a `BadRequestHttpException` if the header is missing. ```php class BlogInfoInterceptor implements Interceptor { public function intercept(ExecutionContext $context, CallHandler $next): mixed { $restContext = $context->switchToRESTContext(); $blogId = $restContext->getWPRequest()->get_header("Blog-Id"); if (!$blogId){ throw new BadRequestHttpException("Blog-Id header is missing."); } switch_to_blog($blogId); $result = $next->handle(); restore_current_blog(); return $result; } } ``` -------------------------------- ### Implementing a Basic Rate Limiting Guard in ModulesPress (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/04-guards.md Provides a simple example of a `RateLimitGuard` using WordPress transients to track requests per IP address. The guard checks if the request count exceeds a threshold within a time window and returns `false` if the limit is reached. ```PHP #[Injectable] class RateLimitGuard implements CanActivate { public function canActivate(ExecutionContext $ctx): bool { $ip = $_SERVER['REMOTE_ADDR']; $key = "rate_limit_" . $ip; $attempts = get_transient($key) ?: 0; if ($attempts >= 100) { // 100 requests per hour return false; } set_transient($key, $attempts + 1, HOUR_IN_SECONDS); return true; } } ``` -------------------------------- ### Configuring Debugging Information Display for Exceptions in PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Shows a protected property `$displayAdditionalDebuggingFor` within a class (like a filter) that lists specific exception types for which detailed debugging information (file, line, trace) should be included in the response when debug mode is enabled. ```php protected array $displayAdditionalDebuggingFor = [ InternalServerErrorHttpException::class, ModuleResolutionException::class ]; ``` -------------------------------- ### Defining ModulesPress Exception Filter Hierarchy in PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Demonstrates how to configure a hierarchical exception filter chain in ModulesPress using a Module's `pluginFilters` method for global filters, `#[UseExceptionFilter]` attribute on a class for class-level filters, and `#[UseExceptionFilter]` on a method for method-level filters. ```php class BookModule extends Module { // Level 3: Plugin Global Filter public function pluginFilters(): array { return [ GlobalExceptionFilter::class ]; } } // Level 2: Class-Level Filter #[UseExceptionFilter(RestExceptionFilter::class)] class BookController { // Level 1: Method-Level Filter #[UseExceptionFilter(SpecificExceptionFilter::class)] public function createBook() { // If an exception occurs here: // 1. Method-level filter tries first // 2. If unhandled, class-level filter tries next // 3. If still unhandled, global filter handles it // 4. Finally, CoreExceptionFilter handles any remaining unhandled exceptions and terminate. } } ``` -------------------------------- ### Example Generated ModulesPress Exception Filter (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md This PHP snippet shows a generated exception filter class structure. It implements the `ExceptionFilter` interface, includes the `#[CatchException]` attribute to specify the exception type to handle, and provides the `catchException` method for custom error responses. ```php #[CatchException(ExceptionType::class)] class FilterName implements ExceptionFilter { public function catchException( BaseException $exception, ExecutionContext $executionContext ): WP_REST_Response | HtmlResponse | JsonResponse {} } ``` -------------------------------- ### Accessing Execution Context Details in ModulesPress Guard (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/04-guards.md Illustrates how guards can utilize the `ExecutionContext` to gain insights into the request context. It shows how to switch to the REST context (`switchToRESTContext`) and access reflections of the class and method, retrieve custom attributes, and get the underlying WordPress request object. ```PHP public function canActivate(ExecutionContext $ctx): bool { $restContext = $ctx->switchToRESTContext(); // Access method reflection $method = $restContext->getMethodReflection(); // Access class reflection $class = $restContext->getClassReflection(); // Get custom attributes $attributes = $method->getAttributes(MyAttribute::class); // Access WP request object $request = $restContext->getWPRequest(); return true; } ``` -------------------------------- ### Attaching Validation Errors to ModulesPress Exception in PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Provides an example of how to create a `ValidationException`, set multiple validation errors using the `setErrors` method, and then throw the exception. These errors will appear in the 'errors' field of the JSON API response. ```php $e = new ValidationException(); $e->setErrors([ "email" => "Invalid email format", "password" => "Must be at least 8 characters" ]); throw $e; ``` -------------------------------- ### Creating Production Package (ModulesPress CLI, Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/08-packaging.md This core ModulesPress CLI command initiates the entire packaging process. It orchestrates tasks including removing development-specific files, optimizing Composer dependencies for production, and finally creating a versioned ZIP archive ready for distribution. ```Bash # Create a production package modulespress pack ``` -------------------------------- ### Packaging ModulesPress Plugin (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md Packages the current ModulesPress plugin for distribution. This process typically includes optimizing dependencies and creating a distribution-ready archive, such as a zip file, for deployment. ```bash modulespress pack ``` -------------------------------- ### Building Frontend Assets (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/08-packaging.md This Bash command executes the `build` script defined in your project's `package.json`. This is typically used to run a frontend build tool like Vite, compiling and optimizing JavaScript, CSS, and other assets for production use. ```Bash # Build Vite assets npm run build ``` -------------------------------- ### Implementing Plugin Ready Lifecycle Method PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/05-plugin-configuration.md Details the `onPluginReady` protected method available in a ModulesPress plugin class. This method is called after the core framework is initialized and all dependencies are resolved, serving as the recommended place for initialization logic that relies on other services or components being available. ```php protected function onPluginReady(ModulesPressPlugin $plugin): void { // This method is called when: // 1. Core framework is initialized // 2. All dependencies are resolved // 3. Before the plugin is fully bootstrapped if ($plugin->isDebugMode()) { // Debug-specific initialization $this->setupDebugTools(); } } ``` -------------------------------- ### Custom Directive WordPress Nonce PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/05-renderer.md Example of a custom Blade directive '@wpNonce' that simplifies adding a WordPress nonce field to a form or page, using the `wp_nonce_field()` function. ```php #[ViewDirective("wpNonce", "onRuntime") safeguard required public function nonceDirective(string $action) { echo wp_nonce_field($action, '_wpnonce', true, false); } ``` -------------------------------- ### Custom Directive Asset Image PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/05-renderer.md Example of a custom Blade directive '@image' that takes an image path parameter and outputs the full URL to the asset using a hypothetical `enquerer` service. ```php #[ViewDirective("image", "onRuntime") safeguard required public function imageDirective(string $imgPath) { echo $this->enquerer->static('imgs/' . $imgPath)->getUrl(); } ``` -------------------------------- ### Importing Modules Including Dynamic Instances - ModulesPress - PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/01-modules.md Illustrates how a module declares its dependencies by importing other modules. This includes importing standard modules by class name and importing instances of dynamic modules, allowing configuration at the point of import. ```php #[Module( imports: [ new BooksDynamicModule(apiVersion: "v1"), AuthModule::class, CoreModule::class ] )] class AdminModule extends ModulesPressModule {} ``` -------------------------------- ### Custom Directive Current Time PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/05-renderer.md Example of a simple custom Blade directive '@currentTime' that outputs the current date and time using PHP's `date()` function when used in a Blade template. ```php #[ViewDirective("currentTime", "onRuntime")] public function currentTimeDirective() { echo date("Y-m-d H:i:s"); } ``` -------------------------------- ### Generating ModulesPress Service Provider (Bash) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/03-cli.md Creates a new PHP class intended to function as a service provider, commonly used for registering services and dependencies. The command requires the desired provider name and supports the optional `--dir, -d` flag. ```bash modulespress make:provider ProviderName ``` -------------------------------- ### Overriding Debugging Configuration in Custom Exception Filter in PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Demonstrates how to extend the `CoreExceptionFilter` and override the `$displayAdditionalDebuggingFor` property in a custom filter class (`CustomExceptionFilter`) to include additional exception types for which debugging details should be shown. ```php class CustomExceptionFilter extends CoreExceptionFilter { protected array $displayAdditionalDebuggingFor = [ InternalServerErrorHttpException::class, ModuleResolutionException::class, DatabaseException::class, CriticalBusinessException::class ]; } ``` -------------------------------- ### Running Production Build Bash Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Provides the command-line instruction to build the plugin's assets for production. This command processes and optimizes assets, generating the necessary files and the manifest file used by the Enquerer to resolve production URLs. ```bash npm run build ``` -------------------------------- ### Enqueuing App Asset with Styles and Localization PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Shows how to enqueue an `AppAsset`, specifically designed for framework applications like React. It includes specifying dependencies, automatically enqueuing associated styles (`withStyles()`), localizing application configuration data, and injecting inline scripts like the static path resolver. ```php // React application with HMR and styles $app = $this->enquerer->app('admin/dashboard/app.tsx') ->dependencies(['wp-element']) ->enqueue() ->withStyles() // enqueue all styles for the app ->localize('appConfig', [ 'environment' => WP_DEBUG ? 'development' : 'production', 'features' => ['analytics', 'reports'] ]); // Add static path resolver and custom configuration $app->inline($this->enquerer->injectStaticPathResolver('staticPath')) ->inline("window.APP_CONFIG = " . json_encode([ 'apiEndpoint' => rest_url($this->plugin->getRestNamespace()), 'maxUploadSize' => wp_max_upload_size() ])); ``` -------------------------------- ### Injecting Enquerer Service PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Demonstrates how to obtain an instance of the ModulesPress Enquerer service within a class by using constructor-based dependency injection, which is the recommended way to use services in ModulesPress. ```php use ModulesPress\Core\Enquerer\Enquerer; class AdminMenuService { public function __construct( private readonly Enquerer $enquerer ) {} } ``` -------------------------------- ### Handling Activation and Deactivation Lifecycle PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/01-getting-started/05-plugin-configuration.md Shows how to implement custom logic for plugin activation (`onActivate`) and deactivation (`onDeactivate`) by overriding the corresponding methods in a `ModulesPressPlugin` subclass. It demonstrates firing custom action hooks (`self::SLUG . '/activate'`, `self::SLUG . '/deactivate'`) within these methods for extensibility. ```php class MyPlugin extends ModulesPressPlugin { public function onActivate(bool $networkWide): void { // Custom activation logic if ($networkWide) { // Network-wide activation handling } // Fires a custom action hook do_action(self::SLUG . '/activate', $networkWide); } public function onDeactivate(): void { // Custom deactivation logic do_action(self::SLUG . '/deactivate'); }l } ``` -------------------------------- ### ModulesPress Basic REST API Error Response in JSON Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Illustrates the default, minimal JSON response structure used by the `CoreExceptionFilter` for REST API errors in ModulesPress. It includes the error message and the corresponding HTTP status code. ```json { "message": "id is required", "statusCode": 400 } ``` -------------------------------- ### Enqueuing Styles for ModulesPress Apps PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/06-enquerer.md Illustrates the correct method to ensure styles are loaded for application assets in ModulesPress by chaining the `withStyles()` method after enqueuing the app, addressing potential style loading issues. ```php // Always use withStyles() for apps with CSS $app->enqueue()->withStyles(); ``` -------------------------------- ### Registering Controller-Level Filter (PHP Attribute) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/07-exception-handling.md Shows how to apply an exception filter specifically to an entire controller using the `#[UseExceptionFilter]` attribute placed above the controller class definition. This filter will process exceptions occurring in any method within that controller. ```PHP #[UseExceptionFilter(RestExceptionFilter::class)] #[RestController("/books")] class BooksController {} ``` -------------------------------- ### Registering WordPress Hooks with Global Functions - PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/03-wordpress-hooks.md Illustrates the traditional WordPress method using global functions and `add_action` for hook registration. This approach pollutes the global namespace, lacks object-oriented context, and complicates dependency management compared to modern techniques. ```php function my_books_init() { // Initialization logic } add_action('init', 'my_books_init'); ``` -------------------------------- ### Rendering Blade View as String PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/05-renderer.md Illustrates rendering a Blade view using the `renderAsString` method to get the rendered HTML as a string instead of outputting it directly. This is useful for cases where the output needs to be processed or stored before being displayed. ```php $viewHtml = $renderer->renderAsString('view-name', [ 'user' => $currentUser, 'settings' => $pluginSettings ]); // return string echo $viewHtml; ``` -------------------------------- ### Applying ModulesPress Middleware using Regex and Exact Paths PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/03-middleware.md This snippet demonstrates applying a middleware (`ApiKeyMiddleware`) to routes matching either a regular expression (`#^api/.*$#`) or an exact path (`books/special`). The `forRoutes` method accepts multiple path arguments for more flexible matching. ```php $consumer->apply(ApiKeyMiddleware::class) ->forRoutes( // Match all routes starting with 'api/' '#^api/.*$#', // Exact route matching 'books/special' ); ``` -------------------------------- ### Implementing CanActivate Guard for REST Nonce PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/07-advanced/01-execution-context.md Defines a class MainGuard implementing the CanActivate interface, demonstrating guard functionality. The canActivate method switches to the REST context and checks for a 'nonce' parameter within the JSON request body. If the nonce is missing, it throws an UnauthorizedHttpException; otherwise, it allows access by returning true. ```php class MainGuard implements CanActivate { public function canActivate(ExecutionContext $executionContext): bool { return true; if (!isset($executionContext->switchToRESTContext()->getWPRequest()->get_json_params()["nonce"])) { throw new UnauthorizedHttpException("You are not authorized to access this resource due to missing nonce."); } else { return true; } } } ``` -------------------------------- ### Defining a Standard Module Structure - ModulesPress - PHP Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/01-modules.md Demonstrates how to define a basic module in ModulesPress using the `#[Module]` attribute. This shows how to declare a module's dependencies (imports), registered services (providers), entry points (controllers), data structures (entities), and components made available to other modules (exports). ```php #[Module( imports: [ AuthModule::class, CategoriesModule::class ], providers: [ BookService::class, BookRepository::class ], controllers: [ BooksController::class ], entities: [ Book::class ], exports: [ BookRepository::class ] )] class BooksModule extends ModulesPressModule {} ``` -------------------------------- ### Implementing Class-Based Dependency Injection (PHP) Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/02-the-basics/02-providers.md Demonstrates how a class (`UserService`) can have its constructor dependencies automatically resolved by the ModulesPress dependency injection container when providers for `EmailService` and `UserRepository` are available. ```php class EmailService { public function sendEmail($to, $subject, $body) { // Email sending logic } } #[Injectable] class UserService { public function __construct( private EmailService $emailService, private UserRepository $userRepository ) {} public function registerUser(User $user) { // Register user logic $this->emailService->sendEmail( $user->email, 'Welcome', 'Thank you for registering' ); } } ``` -------------------------------- ### Defining User Roles using PHP Enum for ModulesPress Guards Source: https://github.com/devsroutes/modulespress-docs/blob/master/docs/03-rest-api/04-guards.md Provides an example of defining user roles using a PHP enum, a common practice for creating type-safe and readable role definitions that can be used in conjunction with guards for role-based access control. ```PHP // Define roles using an enum enum UserRole: string { case SUPER_ADMIN = "cm_super_admin"; case CHAPTER_ADMIN = "cm_chapter_admin"; case CHAPTER_MEMBER = "cm_chapter_member"; } ```