PluginProbe ʕ •ᴥ•ʔ
WooCommerce PayPal Payments / 3.3.2
WooCommerce PayPal Payments v3.3.2
4.0.4 4.0.3 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.4.0 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.7.0 1.7.1 1.8.0 1.8.1 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1.0 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.4.0 2.4.1 2.4.2 2.4.3 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.6.0 2.6.1 2.7.0 2.7.1 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 4.0.0 4.0.1 4.0.2
woocommerce-paypal-payments / docs / plugin-architecture.md
woocommerce-paypal-payments / docs Last commit date
inbox-notifications-guide.md 4 months ago missing-shipping-address-or-other-required-field.md 7 months ago plugin-architecture.md 7 months ago woocommerce-tasks-guide.md 9 months ago
plugin-architecture.md
308 lines
1 # Plugin Architecture Documentation
2
3 This document provides a comprehensive overview of the WooCommerce PayPal Payments plugin architecture, explaining its modular design and how the various components work together.
4
5 ## Overview
6
7 The WooCommerce PayPal Payments plugin is built using a modular architecture powered by the [](https://github.com/inpsyde/modularitySyde Modularity](https://github.com/inpsyde/modularity](https://github.com/inpsyde/modularity) framework. This design provides:
8
9 - **Modular Structure**: Each feature is contained within its own module with clear boundaries
10 - **Dependency Injection**: PSR-11 container for service management and dependency resolution
11 - **Feature Flags**: Dynamic module loading based on environment variables and filters
12 - **Extensibility**: Well-defined extension points for customization and enhancement
13 - **Maintainability**: Clear separation of concerns and consistent patterns
14
15 ## Core Components
16
17 ### Main Plugin File
18
19 The plugin initialization begins in `woocommerce-paypal-payments.php`, which:
20 - Loads the Composer autoloader if needed (e.g. may be already loaded in some tests)
21 - Contains plugin metadata and constants definitions
22 - It starts the bootstrap process, in `plugins_loaded` hook.
23
24 ### Bootstrap System
25
26 The bootstrap process is handled by `bootstrap.php`, which:
27
28 ```php
29 return function (
30 string $root_dir,
31 array $additional_containers = array(),
32 array $additional_modules = array()
33 ): ContainerInterface {
34 // Load modules from modules.php
35 $modules = ( require "$root_dir/modules.php" )( $root_dir );
36
37 // Apply filters for customization
38 $modules = apply_filters( 'woocommerce_paypal_payments_modules', $modules );
39
40 // Initialize plugin with Syde Modularity
41 $properties = PluginProperties::new( "$root_dir/woocommerce-paypal-payments.php" );
42 $bootstrap = Package::new( $properties );
43
44 foreach ( $modules as $module ) {
45 $bootstrap->addModule( $module );
46 }
47
48 $bootstrap->boot();
49 return $bootstrap->container();
50 };
51 ```
52
53 ### PPCP Container
54
55 The global `PPCP` class (`src/PPCP.php`) provides access to the dependency injection container:
56
57 ```php
58 class PPCP {
59 private static $container = null;
60
61 public static function container(): ContainerInterface {
62 if ( ! self::$container ) {
63 throw new LogicException( 'No PPCP container, probably called too early when the plugin is not initialized yet.' );
64 }
65 return self::$container;
66 }
67 }
68 ```
69
70 This allows third-party access services easily, such as in `api/order-functions.php`.
71
72 ## Module System
73
74 ### Module Definition
75
76 Modules are defined in `modules.php` with both core and conditional modules:
77
78 ```php
79 $modules = array(
80 new PluginModule(),
81 ( require "$modules_dir/woocommerce-logging/module.php" )(),
82 ( require "$modules_dir/ppcp-admin-notices/module.php" )(),
83 ( require "$modules_dir/ppcp-api-client/module.php" )(),
84 // ... more core modules
85 );
86 ```
87
88 ### Feature-Flag Controlled Modules
89
90 Conditional modules are loaded based on environment variables and filters (`modules.php`):
91
92 ```php
93 if ( apply_filters(
94 'woocommerce.feature-flags.woocommerce_paypal_payments.applepay_enabled',
95 getenv( 'PCP_APPLEPAY_ENABLED' ) !== '0'
96 ) ) {
97 $modules[] = ( require "$modules_dir/ppcp-applepay/module.php" )();
98 }
99 ```
100
101 This pattern allows for:
102 - **Environment-based control**: Use `PCP_*_ENABLED` environment variables
103 - **Runtime filtering**: Apply WordPress filters to override defaults
104 - **Graceful degradation**: Missing features don't break core functionality
105
106 ### Module Structure
107
108 Each module follows a consistent directory structure:
109
110 ```
111 modules/ppcp-example/
112 ├── module.php # Module factory function
113 ├── composer.json # PHP dependencies
114 ├── package.json # JavaScript dependencies
115 ├── webpack.config.js # Asset building configuration
116 ├── services.php # Service definitions
117 ├── extensions.php # Service extensions/modifications
118 ├── src/ # PHP source code
119 │ └── ExampleModule.php
120 ├── resources/ # Source assets
121 │ ├── js/
122 │ └── css/
123 └── assets/ # Built assets
124 ├── js/
125 └── css/
126 ```
127
128 ### Module Interface Implementation
129
130 Most modules implement the Syde Modularity interfaces. For example in `modules/ppcp-api-client/src/ApiModule.php`:
131
132 ```php
133 class ApiModule implements ServiceModule, FactoryModule, ExtendingModule, ExecutableModule {
134 use ModuleClassNameIdTrait;
135
136 public function services(): array {
137 return require __DIR__ . '/../services.php';
138 }
139
140 public function factories(): array {
141 return require __DIR__ . '/../factories.php';
142 }
143
144 public function extensions(): array {
145 return require __DIR__ . '/../extensions.php';
146 }
147
148 public function run( ContainerInterface $c ): bool {
149 // Module initialization logic
150 return true;
151 }
152 }
153 ```
154
155 ## Key Modules
156
157 ### Core Infrastructure Modules
158
159 - **PluginModule** (`src/PluginModule.php`): Root module providing core services
160 - **woocommerce-logging**: Logging infrastructure integration
161 - **ppcp-api-client**: PayPal API integration, entities, and authentication
162 - **ppcp-session**: Session management for payment flows
163 - **ppcp-webhooks**: PayPal webhook handling
164
165 ### Payment & Checkout Modules
166
167 - **ppcp-button**: PayPal Smart Payment Buttons and Advanced Credit and Debit Cards functionality
168 - **ppcp-blocks**: WooCommerce Blocks integration
169 - **ppcp-wc-gateway**: WooCommerce gateway integration
170 - **ppcp-axo**: PayPal Fastlane (Accelerated Checkout) implementation
171
172 ### Feature Modules
173
174 - **ppcp-settings**: New React-based admin settings interface
175 - **ppcp-vaulting**: Saved payment methods functionality
176 - **ppcp-onboarding**: Merchant onboarding flow
177
178 ### Alternative Payment Methods
179
180 - **ppcp-applepay/ppcp-googlepay**: Digital wallet integrations
181 - **ppcp-local-alternative-payment-methods**: Regional payment options
182
183 ## Dependency Injection & Services
184
185 ### Service Definition
186
187 Services are defined in each module's `services.php` file using factory functions:
188
189 ```php
190 return array(
191 'example.service' => static function ( ContainerInterface $container ): ExampleService {
192 return new ExampleService(
193 $container->get( 'dependency.service' )
194 );
195 },
196
197 'example.config' => static function (): array {
198 return array(
199 'setting' => 'value',
200 );
201 },
202 );
203 ```
204
205 ### Service Extensions
206
207 The `extensions.php` files allow modules to modify or extend existing services:
208
209 ```php
210 return array(
211 'existing.service' => static function ( ContainerInterface $container, ExistingService $service ): ExistingService {
212 // Modify or wrap the existing service
213 return new EnhancedService( $service );
214 },
215 );
216 ```
217
218 ### Container Access Patterns
219
220 Services can be accessed in multiple ways:
221
222 ```php
223 // In our modules/services/extensions (also often passed to hook handlers via `use`)
224 $service = $container->get( 'service.id' );
225
226 // In third-party plugins etc. (if not adding a custom module via the `woocommerce_paypal_payments_modules` filter)
227 $service = PPCP::container()->get( 'service.id' );
228
229 // Check for service availability
230 if ( $container->has( 'optional.service' ) ) {
231 $service = $container->get( 'optional.service' );
232 }
233 ```
234
235 ## Asset Management
236
237 ### Webpack Configuration
238
239 Each module with JavaScript assets includes a `webpack.config.js`:
240
241 ```javascript
242 const path = require('path');
243 const defaultConfig = require('@wordpress/scripts/config/webpack.config');
244
245 module.exports = {
246 ...defaultConfig,
247 entry: {
248 'boot': path.resolve(process.cwd(), 'resources/js', 'boot.js'),
249 },
250 output: {
251 path: path.resolve(process.cwd(), 'assets/js'),
252 filename: '[name].js',
253 },
254 };
255 ```
256
257 ### Build Process
258
259 Assets are built using the shared configuration:
260
261 - **Individual builds**: `yarn run build:modules:ppcp-{module-name}`
262 - **Watch mode**: `yarn run watch:modules:ppcp-{module-name}`
263 - **All modules**: `yarn run build:modules` (parallel builds)
264
265 ### Asset Registration
266
267 Built assets are registered through module services and enqueued conditionally:
268
269 ```php
270 'asset.example-script' => static function( ContainerInterface $container ): Asset {
271 return new Asset(
272 'example-script',
273 plugin_dir_url( __DIR__ ) . 'assets/js/example.js',
274 array( 'wp-element' ), // dependencies
275 '1.0.0'
276 );
277 },
278 ```
279
280 ## Extension Points
281
282 ### WordPress Hooks
283
284 The plugin provides numerous action and filter hooks:
285
286 ```php
287 // Allow modification of order request data
288 apply_filters( 'ppcp_create_order_request_body_data', $data );
289
290 // PayPal order creation notification
291 do_action( 'woocommerce_paypal_payments_paypal_order_created', $order );
292
293 // API cache clearing
294 do_action( 'woocommerce_paypal_payments_flush_api_cache' );
295 ```
296
297 ### Module Filters
298
299 Modules can be modified via filters:
300
301 ```php
302 // Add or remove modules
303 $modules = apply_filters( 'woocommerce_paypal_payments_modules', $modules );
304
305 // Feature flag overrides
306 apply_filters( 'woocommerce.feature-flags.woocommerce_paypal_payments.applepay_enabled', $default );
307 ```
308