diff --git a/.claude/plans/route-domain-refactoring.md b/.claude/plans/route-domain-refactoring.md deleted file mode 100644 index 65117233..00000000 --- a/.claude/plans/route-domain-refactoring.md +++ /dev/null @@ -1,162 +0,0 @@ -# Étude : Refactoring Route.php — Découplage Domain/Infrastructure - -## Problème - -`src/Route/Domain/Models/Route.php` extends `Illuminate\Routing\Route` directement dans la couche Domain. C'est la dernière violation DDD majeure du framework. - -### Pourquoi c'est structurant - -- Le Domain routing est couplé à l'implémentation Laravel -- 13 fichiers (5 src + 8 tests) référencent directement cette classe -- 4 middlewares font des `instanceof Route` checks -- Le `matches()` override contient la logique métier WordPress (condition functions) -- `ExtendedRouter` remplace le router Laravel pour créer nos instances Route -- Les macros `Route::wp()` et `Route::wpMatch()` manipulent directement les properties WordPress - -### Ce que Route.php ajoute à IlluminateRoute - -**4 properties WordPress :** -- `$isWordPressRoute: bool` -- `$condition: string` (ex: `is_single`, `is_page`) -- `$conditionParameters: array` -- `$conditionResolver: ConditionResolverInterface` - -**8 méthodes WordPress :** -- `setIsWordPressRoute()` / `isWordPressRoute()` -- `setCondition()` / `getCondition()` / `hasCondition()` -- `setConditionParameters()` / `getConditionParameters()` -- `setConditionResolver()` - -**1 override :** -- `matches()` — diverge entre matching WordPress (condition function) et matching Laravel (URI pattern) - -**Méthodes héritées utilisées par les consumers :** -- `getAction()`, `setParameter()`, `parameter()`, `hasParameter()`, `uri()`, `getCompiled()`, `middleware()` - ---- - -## Approche recommandée : Composition + Interface - -### Étape 1 — Créer `WordPressRouteInterface` (Domain) - -```php -// src/Route/Domain/Contracts/WordPressRouteInterface.php -interface WordPressRouteInterface -{ - public function isWordPressRoute(): bool; - public function setIsWordPressRoute(bool $isWordPressRoute): static; - public function getCondition(): string; - public function setCondition(string $condition): static; - public function hasCondition(): bool; - public function getConditionParameters(): array; - public function setConditionParameters(array $parameters): static; - public function setConditionResolver(ConditionResolverInterface $resolver): static; -} -``` - -### Étape 2 — Déplacer Route vers Infrastructure - -``` -src/Route/Domain/Models/Route.php - → src/Route/Infrastructure/Models/Route.php -``` - -Le namespace change : `Pollora\Route\Infrastructure\Models\Route`. - -La classe reste identique (extends IlluminateRoute + implements WordPressRouteInterface). Le couplage Laravel est désormais dans la couche Infrastructure où il a sa place. - -### Étape 3 — Mettre à jour les imports (13 fichiers) - -| Fichier | Action | -|---------|--------| -| `ExtendedRouter.php` | Update import | -| `WordPressRoutingService.php` | Type-hint → `WordPressRouteInterface` | -| `WordPressBindings.php` | `instanceof WordPressRouteInterface` | -| `WordPressBodyClass.php` | `instanceof WordPressRouteInterface` — **attention** : utilise aussi des méthodes héritées Laravel (`getCompiled`, `parameter`, `hasParameter`) | -| `WordPressHeaders.php` | `method_exists` → `instanceof WordPressRouteInterface` | -| `BindWordPressParametersUseCase.php` | Type-hint → `WordPressRouteInterface` — **attention** : utilise `getAction()`, `setParameter()`, `uri()` | -| `RouteServiceProvider.php` | Macros utilisent `$route->setIsWordPressRoute()` etc. | -| 8 fichiers tests | Update imports | - -### Étape 4 — Problème `BindWordPressParametersUseCase` (Application layer) - -Ce use case est dans la couche Application et utilise : -- `$route->getAction()` — méthode de IlluminateRoute, pas de WordPressRouteInterface -- `$route->setParameter()` — idem -- `$route->uri()` — idem - -**Options :** -1. **Étendre l'interface** avec ces méthodes (mais ça tire les concepts Laravel dans le Domain) -2. **Créer une interface `RoutableInterface`** dans Domain avec `getAction()`, `setParameter()`, `uri()`, `parameter()`, `hasParameter()` — ces concepts sont assez génériques pour exister au niveau Domain -3. **Garder le type Laravel `Illuminate\Routing\Route`** dans le use case (le use case est Application, pas Domain — acceptable) - -**Recommandation :** Option 3 pour l'instant. Le use case accepte `Illuminate\Routing\Route` directement — c'est la couche Application, elle peut dépendre de l'Infrastructure. Seul le Domain doit rester pur. - -### Étape 5 — Problème `WordPressBodyClass` middleware - -Utilise des méthodes Laravel (`getCompiled()`, `parameter()`, `hasParameter()`) : -- C'est un middleware Infrastructure — acceptable d'utiliser le type concret `Route` -- Ou bien : type-hint `Illuminate\Routing\Route` pour les méthodes Laravel + `instanceof WordPressRouteInterface` pour les méthodes WordPress - -### Étape 6 — Backward compatibility - -Ajouter un class_alias dans `RouteServiceProvider` : -```php -if (! class_exists('Pollora\\Route\\Domain\\Models\\Route')) { - class_alias(Route::class, 'Pollora\\Route\\Domain\\Models\\Route'); -} -``` - ---- - -## Impact estimé - -| Métrique | Valeur | -|----------|--------| -| Fichiers source modifiés | 7 | -| Fichiers tests modifiés | 8 | -| Nouveau fichier | 1 (WordPressRouteInterface) | -| Risque | **Moyen** — le routing est critique, mais le changement est structurel (move + interface), pas fonctionnel | -| Effort | ~1-2h | -| Bénéfice | Domain 100% pur des imports `Illuminate\Routing\*` | - -## Résultat après refactoring - -### Violations Domain `Illuminate\*` restantes - -| Fichier | Import | Status | -|---------|--------|--------| -| `ModuleCollection.php` | extends `Collection` | **Accept** — Collection est quasi-standard | -| `PluginCollection.php` | extends `Collection` | **Accept** — idem | -| `DiscoveryEngineInterface.php` | retourne `Collection` | **Accept** — interface publique | -| ~~`Route.php`~~ | ~~extends `IlluminateRoute`~~ | ✅ **Résolu** — déplacé en Infrastructure | - -**Domain violations : 4 → 3** (les 3 restantes sont toutes `Collection`, un trade-off accepté). - ---- - -## Pré-requis - -- Branche `release/v13.4.0` ou nouvelle branche feature -- 999 tests doivent continuer à passer -- PHPStan 0 erreurs -- Pint clean -- 67 tests intégration skeleton verts - -## Vérification - -```bash -ddev exec --dir /var/www/html/vendor/pollora/framework composer test -ddev composer test:integration -``` - -## Ordre d'implémentation suggéré - -1. Créer `WordPressRouteInterface` dans Domain/Contracts -2. Faire implémenter l'interface par `Route.php` -3. `git mv` Route.php vers Infrastructure/Models -4. Mettre à jour les 5 fichiers source (imports, type-hints) -5. Ajouter le class_alias backward compat -6. Mettre à jour les 8 fichiers tests -7. Mettre à jour le baseline PHPStan (les macros sont dans le baseline) -8. Vérifier les 999 tests + 67 intégration \ No newline at end of file diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index 5d36a5a0..00000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,19 +0,0 @@ -engines: - phpcodesniffer: - enabled: true - config: - file_extensions: "php" - standard: "PSR1,PSR2" - ignore_warnings: true - encoding: utf-8 - phpmd: - enabled: true - config: - file_extensions: "php" - rulesets: "codesize,controversial,design,phpmd.xml" - checks: - CyclomaticComplexity: - enabled: false -ratings: - paths: - - "**.php" diff --git a/.cursor/rules/pollora-architecture.mdc b/.cursor/rules/pollora-architecture.mdc deleted file mode 100644 index 66d4fffb..00000000 --- a/.cursor/rules/pollora-architecture.mdc +++ /dev/null @@ -1,43 +0,0 @@ ---- -description: Pollora Framework - Domain-Driven Design Architecture -alwaysApply: true ---- - -# Pollora DDD Architecture Standards - -## Strict Module Structure -Always follow the DDD module structure for new components: - -``` -src/[Module]/ -├── Application/Services/ # Application layer - use cases and orchestration -├── Domain/ -│ ├── Contracts/ # Interfaces and contracts -│ ├── Models/ # Domain entities and value objects -│ ├── Services/ # Domain services and business logic -│ └── Exceptions/ # Domain-specific exceptions -├── Infrastructure/ -│ ├── Providers/ # Service providers for DI container -│ ├── Repositories/ # Data persistence implementations -│ ├── Services/ # Infrastructure services (external concerns) -│ └── Adapters/ # Adapters for external systems -└── UI/ - ├── Console/ # Artisan commands - └── Http/ # HTTP controllers and middleware -``` - -## Layer Responsibilities -- **Domain**: Business logic, entities, contracts - NO external dependencies -- **Application**: Use cases, orchestration - depends only on Domain -- **Infrastructure**: Technical implementations, databases, external APIs -- **UI**: Controllers, commands, presentation logic - -## Namespace Conventions -- Framework classes: `Pollora\[Module]\[Layer]\` -- Theme classes: `Theme\{ThemeName}\` (dynamically autoloaded) -- Plugin classes: `Plugin\{PluginName}\` (future support) - -## Service Provider Registration -- Each module MUST have a dedicated service provider -- Register in dependency order within `PolloraServiceProvider` -- WordPress services registered AFTER Laravel core services \ No newline at end of file diff --git a/.cursor/rules/pollora-attributes.mdc b/.cursor/rules/pollora-attributes.mdc deleted file mode 100644 index 74ba37c4..00000000 --- a/.cursor/rules/pollora-attributes.mdc +++ /dev/null @@ -1,68 +0,0 @@ ---- -description: Pollora Framework - PHP 8 Attributes for Declarative Configuration -globs: ["**/*.php"] -alwaysApply: false ---- - -# Attribute-Driven Configuration - -## Available Attributes -Use these PHP 8 attributes for declarative configuration: - -### WordPress Integration -```php -#[PostType( - name: 'custom_post', - args: ['public' => true, 'supports' => ['title', 'editor']] -)] -class CustomPost {} - -#[Taxonomy( - name: 'custom_taxonomy', - postTypes: ['post', 'custom_post'], - args: ['hierarchical' => true] -)] -class CustomTaxonomy {} - -#[Action( - hook: 'init', - priority: 10, - acceptedArgs: 1 -)] -public function initMethod() {} - -#[Filter( - hook: 'the_content', - priority: 10, - acceptedArgs: 1 -)] -public function filterContent(string $content): string {} -``` - -### Scheduling & REST API -```php -#[Schedule( - cron: '0 0 * * *', - method: 'dailyTask' -)] -class ScheduledTask {} - -#[WpRestRoute( - endpoint: '/custom/v1/data', - methods: ['GET', 'POST'] -)] -public function handleRestRequest() {} -``` - -## Best Practices -- Use attributes instead of manual hook registration -- Place attributes directly above the class or method they configure -- Keep attribute parameters declarative and simple -- The Discovery system will automatically find and register these attributes -- Prefer convention over configuration where possible - -## Discovery System -- Classes with attributes are automatically discovered by `Discoverer` module -- No manual registration needed for attributed classes -- Follows convention-over-configuration approach -- Attributes are processed during service provider boot phase \ No newline at end of file diff --git a/.cursor/rules/pollora-autoloading.mdc b/.cursor/rules/pollora-autoloading.mdc deleted file mode 100644 index d1dd1eaa..00000000 --- a/.cursor/rules/pollora-autoloading.mdc +++ /dev/null @@ -1,53 +0,0 @@ ---- -description: Pollora Framework - Dynamic Autoloading System -globs: ["themes/**/app/**/*.php", "themes/**/src/**/*.php", "plugins/**/app/**/*.php"] -alwaysApply: false ---- - -# Dynamic Autoloading System - -## Namespace Conventions -**Fixed namespace patterns** for automatic PSR-4 autoloading: - -### Themes -- **Namespace**: `Theme\{ThemeName}\` -- **Directory**: `themes/{theme-name}/app/` (preferred) or `themes/{theme-name}/src/` (fallback) - -Example: -```php -// File: themes/solidarmonde/app/Providers/ThemeServiceProvider.php -namespace Theme\Solidarmonde\Providers; - -class ThemeServiceProvider extends ServiceProvider {} -``` - -### Plugins (Future Support) -- **Namespace**: `Plugin\{PluginName}\` -- **Directory**: `plugins/{plugin-name}/app/` or `plugins/{plugin-name}/src/` - -## Directory Structure -``` -themes/solidarmonde/ -├── app/ # PSR-4 autoloaded (preferred) -│ ├── Providers/ -│ │ └── ThemeServiceProvider.php -│ ├── Models/ -│ ├── Services/ -│ └── Controllers/ -├── src/ # PSR-4 autoloaded (fallback) -└── views/ # NOT autoloaded -``` - -## Autoloading Flow -1. `ModuleBootstrap` discovers service providers -2. `ThemeServiceProviderScout` scans for providers -3. `LaravelThemeModule::register()` calls `registerAutoloading()` -4. `ThemeAutoloader` maps namespaces to directories -5. Classes become accessible with proper namespace - -## Best Practices -- Use `app/` directory for new themes (preferred over `src/`) -- Follow PSR-4 standards for class naming -- Service providers are automatically discovered -- No manual composer.json modifications needed -- Namespace must match theme/plugin directory name (PascalCase) diff --git a/.cursor/rules/pollora-dependency-injection.mdc b/.cursor/rules/pollora-dependency-injection.mdc deleted file mode 100644 index 06f0275e..00000000 --- a/.cursor/rules/pollora-dependency-injection.mdc +++ /dev/null @@ -1,131 +0,0 @@ ---- -description: Pollora Framework - Dependency Injection & Service Resolution Best Practices -globs: ["**/*.php"] -alwaysApply: false ---- - -# Dependency Injection & Service Resolution - -## NEVER Use Laravel Facades -❌ **Avoid Laravel facades** - Always use the original classes: - -```php -// ❌ DON'T -use Illuminate\Support\Facades\Cache; -Cache::get('key'); - -// ✅ DO -use Illuminate\Cache\Repository; -class MyService { - public function __construct(private Repository $cache) {} -} -``` - -## Service Resolution Priority - -### 1. Dependency Injection (PREFERRED) -✅ **Always prefer constructor injection or method injection when possible:** - -```php -class MyServiceProvider extends ServiceProvider -{ - public function __construct( - private Action $action, - private Filter $filter - ) {} - - public function boot(Action $action, Filter $filter): void - { - // Method injection in boot() is supported - $action->add('init', $this->initMethod(...)); - } -} -``` - -### 2. Container Resolution -When dependency injection isn't possible, use container resolution: - -```php -// ✅ PREFERRED: app()->get() (better performance) -$action = $this->app->get(Action::class); -$filter = $this->app->get(Filter::class); - -// ✅ ALTERNATIVE: app()->make() (when get() isn't available) -$service = $this->app->make(SomeService::class); -``` - -## WordPress Hooks Integration - -### Available Hook Services -Use Pollora's dedicated hook services instead of direct WordPress functions: - -```php -use Pollora\Hook\Infrastructure\Services\Action; -use Pollora\Hook\Infrastructure\Services\Filter; -``` - -### Service Resolution for Hooks -```php -class MyServiceProvider extends ServiceProvider -{ - private Action $action; - private Filter $filter; - - public function boot(): void - { - // Resolve hook services - $this->action = $this->app->get(Action::class); - $this->filter = $this->app->get(Filter::class); - - $this->registerHooks(); - } -} -``` - -### Hook Registration Examples -```php -private function registerHooks(): void -{ - // Actions - $this->action->add('after_setup_theme', $this->registerMenus(...), 1); - $this->action->add('init', $this->initMethod(...), 10); - - // Filters - $this->filter->add('nav_menu_link_attributes', $this->handleLinkAttributes(...), 10, 4); - $this->filter->add('nav_menu_item_attributes', $this->handleItemAttributes(...), 10, 4); - $this->filter->add('nav_menu_submenu_attributes', $this->handleSubmenuAttributes(...), 10, 3); - $this->filter->add('the_content', $this->modifyContent(...), 20, 1); -} -``` - -### Available Hook Methods -Both `Action` and `Filter` services provide: - -```php -// Add hooks -$this->action->add('hook_name', $callback, $priority, $accepted_args); -$this->filter->add('hook_name', $callback, $priority, $accepted_args); - -// Remove hooks -$this->action->remove('hook_name', $callback, $priority); -$this->filter->remove('hook_name', $callback, $priority); - -// Execute hooks -$this->action->do('hook_name', ...$args); -$result = $this->filter->apply('hook_name', $value, ...$args); -``` - -## Best Practices Summary - -1. **Never use Laravel facades** - always use original classes -2. **Prioritize dependency injection** in constructors and methods -3. **Use `app()->get()`** for better performance when DI isn't possible -4. **Use `app()->make()`** only when `get()` isn't available -5. **Use Pollora hook services** instead of direct `add_action`/`add_filter` -6. **Resolve hook services once** and reuse the instances -7. **Register hooks in service provider `boot()` method** - -## Performance Notes -- `app()->get()` is faster than `app()->make()` for singleton services -- Dependency injection is the most performant option -- Cache service instances when possible to avoid repeated resolution diff --git a/.cursor/rules/pollora-service-providers.mdc b/.cursor/rules/pollora-service-providers.mdc deleted file mode 100644 index 2747e15c..00000000 --- a/.cursor/rules/pollora-service-providers.mdc +++ /dev/null @@ -1,54 +0,0 @@ ---- -description: Pollora Framework - Service Provider Patterns -globs: ["**/*ServiceProvider.php", "**/Providers/**/*.php"] -alwaysApply: false ---- - -# Service Provider Standards - -## Service Provider Structure -Always follow this pattern for service providers: - -```php -app->bind(ContractInterface::class, ConcreteImplementation::class)` -- Use singletons for stateless services: `$this->app->singleton()` -- Tag related services: `$this->app->tag([...], 'tag-name')` - -## WordPress Integration -- WordPress hooks registration happens in service provider `boot()` method -- Use Laravel's service container within WordPress hooks -- Ensure WordPress is loaded before accessing WordPress functions diff --git a/.cursor/rules/pollora-testing-quality.mdc b/.cursor/rules/pollora-testing-quality.mdc deleted file mode 100644 index 0009b7c4..00000000 --- a/.cursor/rules/pollora-testing-quality.mdc +++ /dev/null @@ -1,52 +0,0 @@ ---- -description: Pollora Framework - Testing & Code Quality Standards -globs: ["**/tests/**/*.php", "**/*Test.php"] -alwaysApply: false ---- - -# Testing & Quality Standards - -## Required Quality Standards -- **Test Coverage**: 100% test coverage required (`--min=100`) -- **Static Analysis**: PHPStan level 5 with WordPress and Laravel extensions -- **Code Style**: Laravel Pint for PHP formatting -- **Refactoring**: Rector with Laravel-specific rules - -## Test Organization -Tests organized by architectural layer: -``` -tests/ -├── Unit/ # Domain logic and services -├── Feature/ # Integration testing across layers -└── Scouts/ # Discovery system component testing -``` - -## Development Commands -```bash -# Run all quality checks -ddev exec --dir /var/www/html/vendor/pollora/framework composer test - -# Individual commands -ddev exec --dir /var/www/html/vendor/pollora/framework composer test:unit # PHPUnit with 100% coverage -ddev exec --dir /var/www/html/vendor/pollora/framework composer test:types # PHPStan static analysis -ddev exec --dir /var/www/html/vendor/pollora/framework composer test:lint # Code formatting check -ddev exec --dir /var/www/html/vendor/pollora/framework composer test:refacto # Refactoring rules check (dry-run) - -# Fix issues -ddev exec --dir /var/www/html/vendor/pollora/framework composer lint # Fix code formatting -ddev exec --dir /var/www/html/vendor/pollora/framework composer refacto # Apply refactoring rules -``` - -## Test Structure -- Unit tests for Domain layer (pure business logic) -- Feature tests for Application layer (use cases) -- Integration tests for Infrastructure layer -- Use Laravel's TestCase with WordPress integration via testbench.yaml - -## Best Practices -- Test behavior, not implementation -- Follow AAA pattern (Arrange, Act, Assert) -- Use meaningful test method names -- Mock external dependencies in unit tests -- Use factories for test data creation -- Test edge cases and error conditions diff --git a/.cursor/rules/pollora-wordpress-integration.mdc b/.cursor/rules/pollora-wordpress-integration.mdc deleted file mode 100644 index e4a2c5cf..00000000 --- a/.cursor/rules/pollora-wordpress-integration.mdc +++ /dev/null @@ -1,60 +0,0 @@ ---- -description: Pollora Framework - WordPress-Laravel Integration Bridge -globs: ["**/WordPress/**/*.php", "**/Bootstrap/**/*.php", "**/Template/**/*.php"] -alwaysApply: false ---- - -# WordPress-Laravel Integration - -## Bootstrap Process -The `WordPress\Bootstrap` class is the critical bridge: -- Manages WordPress constants and configuration -- Handles database configuration mapping -- Controls WordPress initialization flow -- Manages URL schemes and routing - -## WordPress Integration Points - -### Database Bridge -Laravel database config automatically maps to WordPress constants: -```php -// Laravel config maps to WordPress -DB_HOST → WordPress DB_HOST -DB_NAME → WordPress DB_NAME -DB_USER → WordPress DB_USER -DB_PASSWORD → WordPress DB_PASSWORD -``` - -### Authentication Integration -- Custom Laravel guards for WordPress authentication -- WordPress-compatible password hashing -- User session management bridge - -### Template System -- Blade templates with WordPress template hierarchy -- `TemplateHierarchy` module for template resolution -- Support for both Blade and PHP templates - -### Asset Management -- Vite integration with HMR support -- Automatic WordPress script/style enqueuing -- Asset containers for theme-specific resources - -## WordPress Compatibility -- Patches applied to WordPress core for Laravel compatibility -- Custom function renaming to avoid conflicts (`__` function, `wp_mail`) -- Conditional WordPress loading (console vs web environment) - -## Best Practices -- Always check if WordPress is loaded before using WordPress functions -- Use Laravel's service container within WordPress hooks -- Prefer Laravel patterns (facades, dependency injection) over global WordPress functions -- WordPress hooks should be registered in service provider `boot()` method -- Use `app()` helper to resolve services within WordPress contexts -- Environment-aware constant definition for WordPress configuration - -## Events System -Comprehensive WordPress event dispatching: -- Core WordPress events (posts, users, comments) -- Plugin-specific events (WooCommerce, Gravity Forms, Yoast SEO) -- Custom application events through Laravel's event system diff --git a/.gitattributes b/.gitattributes index 5c247f99..67c2e50d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,16 +1,10 @@ # Left out of the archive Composer installs: what only developing the # framework needs. The browser tests stay reachable by cloning the repository, # which is how theme CI fetches them. -/.claude export-ignore -/.codeclimate.yml export-ignore -/.cursor export-ignore /.github export-ignore /.gitattributes export-ignore /.gitmodules export-ignore /.husky export-ignore -/.php-cs-fixer.cache export-ignore -/.styleci.yml export-ignore -/.windsurf export-ignore /CLAUDE.md export-ignore /commitlint.config.js export-ignore /documentation export-ignore diff --git a/.gitignore b/.gitignore index 616608d4..826436d0 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ claude framework.code-workspace examples/ .claude/ + +# Editor and AI-assistant settings stay local; project guidelines live in CLAUDE.md and Nectar +/.cursor/ +/.windsurf/ diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache deleted file mode 100644 index 0fcca98b..00000000 --- a/.php-cs-fixer.cache +++ /dev/null @@ -1 +0,0 @@ -{"php":"8.0.29","version":"3.8.0:v3.8.0#cbad1115aac4b5c3c5540e7210d3c9fba2f81fa3","indent":" ","lineEnding":"\n","rules":{"array_syntax":{"syntax":"short"}},"hashes":{"src\/Mail\/Mailer.php":1660177352,"src\/Models\/Comment.php":3873229117,"src\/Models\/Post.php":1798921485,"src\/Support\/WordPress.php":3587404917,"src\/Proxy\/WordPressCache.php":3603413932,"src\/Proxy\/WordPressDatabase.php":1855621534,"src\/helpers.php":440031269,"src\/Route\/Matching\/ConditionValidator.php":2986620342,"src\/Route\/Route.php":2274020461,"src\/Providers\/WordPressServiceProvider.php":1520812535,"src\/Providers\/WordPressTemplatingServiceProvider.php":1700811233,"src\/Hook\/ActionBuilder.php":1440079012,"src\/Hook\/FilterBuilder.php":2681353283,"src\/Hook\/Hook.php":1499477558}} \ No newline at end of file diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 1c53b1a6..00000000 --- a/.styleci.yml +++ /dev/null @@ -1,35 +0,0 @@ -preset: laravel - -risky: true - -enabled: - - unalign_double_arrow - - combine_consecutive_unsets - - concat_with_spaces - - dir_constant - - ereg_to_preg - - linebreak_after_opening_tag - - modernize_types_casting - - no_blank_lines_before_namespace - - no_empty_comment - - no_php4_constructor - - no_short_echo_tag - - no_useless_else - - ordered_class_elements - - ordered_imports - - php_unit_construct - - php_unit_dedicate_assert - - php_unit_strict - - phpdoc_order - - phpdoc_property - - phpdoc_separation - - random_api_migration - - semicolon_after_instruction - - strict_comparison - - strict_param - -disabled: - - concat_without_spaces - - single_blank_line_before_namespace - - not_operator_with_successor_space - - length_ordered_imports diff --git a/.windsurf/rules/guidelines.md b/.windsurf/rules/guidelines.md deleted file mode 100644 index a0d08c90..00000000 --- a/.windsurf/rules/guidelines.md +++ /dev/null @@ -1,260 +0,0 @@ ---- -trigger: always_on -description: -globs: ---- - -# Pollora & PHP Coding Standards for AI Code Assistants - -This document outlines the Pollora and PHP development standards, structured for optimal compatibility with AI tools such as GitHub Copilot, Cursor, and Claude Code. These conventions are adapted from Spatie’s Laravel & PHP guidelines. - -## Laravel Foundation - -**Always follow official Laravel conventions first.** Deviation is acceptable only when justified by a valid technical reason. - -## PHP Standards - -* Adhere to PSR-1, PSR-2, and PSR-12 -* Use `camelCase` for all internal string keys and parameters -* Prefer `?Type` over `Type|null` -* Explicitly return `void` when nothing is returned - -## Class Design - -* Use typed properties, not docblocks -* Use constructor property promotion when applicable -* Declare one trait per line - -## Typing & Docblocks - -* Favor typed properties over annotations -* Define return types, including `void` -* Use generics for iterable types: - - ```php - /** @return Collection */ - public function users(): Collection - ``` - -### Docblock Rules - -* Avoid docblocks for fully typed methods (unless needed for clarity) -* Always import class names in docblocks: - - ```php - use Pollora\Url\Url; - /** @return Url */ - ``` -* Use one-line annotations where applicable: `/** @var string */` -* For multi-type hints, list the most common type first: - - ```php - /** @var Collection|Custom\Collection */ - ``` -* If one parameter has a docblock, all should -* Always define key/value for iterables: - - ```php - /** - * @param array $items - * @param int $id - */ - function process(array $items, int $id): void {} - ``` -* Use array shape syntax for structured arrays: - - ```php - /** @return array{ - first: SomeClass, - second: SomeClass - } */ - ``` - -## Control Flow - -* Handle edge cases first (happy path last) -* Prefer early return over `else` -* Avoid compound conditions; separate `if` statements improve clarity -* Always use curly braces `{}` even for single-line blocks -* Format ternary operators for readability - -```php -if (! $user) { - return null; -} - -if (! $user->isActive()) { - return null; -} - -// Handle active user -``` - -```php -$name = $isFoo ? 'foo' : 'bar'; - -$result = $item instanceof Model - ? $item->name - : 'default'; -``` - -## Pollora-Specific Conventions - -### Routes - -* URL paths: kebab-case (`/open-source`) -* Route names: camelCase (`->name('openSource')`) -* Parameters: camelCase (`{userId}`) -* Controller references: tuple syntax `[Controller::class, 'method']` - -### Controllers - -* Use plural resource names (`PostsController`) -* Stick to standard CRUD methods -* Isolate non-CRUD logic into dedicated controllers - -### Configuration - -* File names: kebab-case (`pdf-generator.php`) -* Keys: snake\_case (`chrome_path`) -* Extend `config/services.php` instead of creating new config files -* Use `config()` for access, not `env()` (outside config files) - -### Artisan Commands - -* Use kebab-case (`delete-old-records`) -* Always give user feedback (`$this->comment('Done')`) -* Output before processing for easier debugging -* Show progress and final summary - -```php -$items->each(function (Item $item) { - $this->info("Processing ID {$item->id}..."); - $this->processItem($item); -}); - -$this->comment("Total: {$items->count()} items processed."); -``` - -## String Handling - -* Prefer interpolation over concatenation - -## Enums - -* Enum values use PascalCase - -## Comments - -* Write expressive code to reduce comment need -* When needed, format clearly: - -```php -// Brief description - -/* - * Multiline block - */ -``` - -* Replace comments with descriptive method names when possible - -## Whitespace - -* Separate logical blocks with blank lines -* No extra spacing between brackets -* Group related single-line operations without separation - -## Validation - -* Use array syntax for rules (makes custom rules easier to inject): - - ```php - return [ - 'email' => ['required', 'email'], - ]; - ``` -* Custom rules use snake\_case: - - ```php - Validator::extend('organisation_type', fn($attribute, $value) => OrganisationType::isValid($value)); - ``` - -## Blade Templates - -* Use 4-space indentation -* No space after control structures: - - ```blade - @if($active) - ... - @endif - ``` - -## Authorization - -* Use camelCase in policies: `Gate::define('editPost', ...)` -* Favor CRUD naming; prefer `view` over `show` - -## Translations - -* Use `__()` instead of `@lang` - -## API Routing - -* Use plural resources: `/errors` -* Use kebab-case: `/error-occurrences` -* Avoid deep nesting: - - ``` - /error-occurrences/1 - /errors/1/occurrences - ``` - -## Testing - -* Where practical, co-locate related test classes -* Use descriptive method names -* Follow arrange–act–assert pattern - ---- - -## Quick Reference - -### Naming - -| Element | Convention | Example | -| ------------------- | ----------- | -------------------------- | -| Classes | PascalCase | `UserController` | -| Methods / Variables | camelCase | `getUserName`, `$userData` | -| Routes | kebab-case | `/open-source` | -| Config Files | kebab-case | `pdf-generator.php` | -| Config Keys | snake\_case | `chrome_path` | -| Artisan Commands | kebab-case | `delete-old-records` | - -### Structure - -* Controllers: `PostsController` -* Views: `openSource.blade.php` -* Jobs: `SendEmailNotification` -* Events: `UserRegistered` -* Listeners: `SendWelcomeMailListener` -* Commands: `PublishScheduledPostsCommand` -* Mailables: `AccountActivatedMail` -* Resources: `UsersResource` -* Enums: `BookingStatus` - -### Migrations - -* Only use `up()` methods, no need for `down()` unless rollback is required - ---- - -## Code Quality Checklist - -* Typed properties > docblocks -* Early return > nested logic -* Use constructor property promotion -* Avoid `else` where possible -* Use string interpolation -* Always use braces for control structures \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 868175f3..82df1452 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Security - WordPress 7.1.3 is a security release (seven fixes, among them a stored XSS on the Comments screen and a second-order SQL injection in the WXR export). The skeleton installs it from v13.35.1; an existing project runs `composer update johnpbloch/wordpress johnpbloch/wordpress-core`. Pollora's core patch still applies +### Removed +- Editor and tool files no longer tracked: `.cursor/` and `.windsurf/` rules from 2025 (superseded by `CLAUDE.md` and Nectar), a `.claude/` plan, a 2023 `.php-cs-fixer.cache`, and the unused StyleCI and Code Climate configurations (style is checked by Pint in CI, coverage by Codecov) + ### Fixed - A plugin that answers from `template_redirect` and includes the theme's query template itself (`include get_query_template('404')`, WooCommerce's Review Order page) printed the Blade source of the view: the `{type}_template` filters now hand back a loader that renders it while `template_redirect` runs (#419) - `template_redirect` ran before the application's providers had booted — WordPress is loaded from a provider's boot, the theme's providers boot after it — so a view rendered from it lacked the theme's view composers and shared data. It now runs once every provider has booted, still before routing, and `pollora_loaded` after it (#419)