Skip to content

Commit 0fc624b

Browse files
authored
Update package template setup to work as a plugin bootstrap (#5)
1 parent 0804d05 commit 0fc624b

27 files changed

+845
-489
lines changed

.github/copilot-instructions.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Copilot Instructions for WP Media Package Template
2+
3+
## Project Overview
4+
WordPress plugin/package template using modern PHP with dependency injection (League Container), event-driven architecture (WP Media EventManager), and comprehensive testing infrastructure.
5+
6+
## Creating a New Plugin from Template
7+
8+
When starting a new plugin project, update these key identifiers:
9+
10+
1. **Namespace**: Find/replace `WPMedia\PackageTemplate``WPMedia\YourPlugin` in:
11+
- `composer.json` autoload sections
12+
- All PHP files in `inc/` and `Tests/`
13+
14+
2. **composer.json**: Update `name`, `description`, `homepage`, text domain
15+
3. **plugin.php**: Update plugin headers (Plugin Name, URI, Description, Text Domain, version)
16+
4. **Config**: Update `plugin_slug` and `prefix` in `plugin.php` Config::init() array
17+
5. **phpcs.xml.dist**: Update `text_domain` and `prefixes` properties for I18n and naming conventions
18+
6. **Hook names**: Replace `wpmedia_package_template_loaded` with your plugin-specific hook in `Plugin.php`
19+
20+
## Architecture
21+
22+
### Core Components
23+
- **`plugin.php`**: Entry point that initializes `Config` and `Plugin` class, registers activation/deactivation hooks
24+
- **`inc/Config.php`**: Singleton config container initialized in `plugin.php` with `version`, `plugin_file`, `plugin_basename`, `plugin_slug`, `prefix`
25+
- **`inc/Plugin.php`**: Main plugin orchestrator with `load()`, `activate()`, `deactivate()` methods; instantiates Container, EventManager, Options
26+
- **`inc/Subscriber.php`**: Event subscribers implementing `SubscriberInterface` with `get_subscribed_events()` returning hooks array
27+
28+
### Dependency Pattern
29+
Plugin uses WP Media packages (not bundled WordPress conventions):
30+
- `wp-media/event-manager`: Event/hook system via `EventManager` + `PluginApiManager`
31+
- `wp-media/options`: Options handling via `Options` class with prefix from Config
32+
- `wp-media/apply-filters-typed`: Type-safe filter application
33+
- `league/container`: PSR-11 dependency injection container
34+
35+
Event subscribers register via `$event_manager->add_subscriber(new Subscriber())` instead of direct `add_action()` calls.
36+
37+
## Development Workflow
38+
39+
### Setup
40+
```bash
41+
composer install
42+
bash bin/install-wp-tests.sh wordpress_test <db_user> <db_pass> localhost latest
43+
```
44+
45+
### Quality Checks
46+
- **Tests**: `composer run-tests` (runs both unit + integration), or separately: `composer test-unit`, `composer test-integration`
47+
- **Code Standards**: `composer phpcs` (check), `composer phpcs:fix` (auto-fix)
48+
- **Static Analysis**: `composer phpstan` (level 5, analyzes `inc/` and `Tests/`)
49+
50+
### Testing Structure
51+
- **Unit tests** (`Tests/Unit/`): Extend `WPMedia\PHPUnit\Unit\TestCase`, use Brain Monkey for WP function mocking
52+
- **Integration tests** (`Tests/Integration/`): Extend `WPMedia\PHPUnit\Integration\TestCase`, run against real WordPress test suite
53+
- Both test base classes support `configTestData()` pattern for loading test fixtures from co-located PHP files
54+
55+
## Code Conventions
56+
57+
### PHP Standards
58+
- **Minimum PHP**: 7.4+ with strict types (`declare(strict_types=1);` in all files)
59+
- **Namespace**: `WPMedia\PackageTemplate` for core, `WPMedia\PackageTemplate\Tests` for tests
60+
- **Coding style**: WordPress Coding Standards with PSR-4 autoloading, short array syntax `[]` enforced
61+
- **Prefixes**: Global functions/hooks use `wpmedia_` prefix, database options use `pt_` prefix (from Config)
62+
63+
### File Naming
64+
- Classes use PascalCase filenames matching class name (e.g., `Plugin.php`, `Subscriber.php`)
65+
- No strict hyphenated-lowercase requirement for class files
66+
67+
### Type Safety
68+
- Use type hints for parameters and return types (`:void`, `:array`, etc.)
69+
- PHPStan level 5 with WordPress stubs for static analysis
70+
- Suppress false positives with `@phpstan-ignore-line` comments
71+
72+
## Integration Points
73+
74+
### Plugin Initialization Flow
75+
1. `plugin.php` loads Composer autoloader
76+
2. `Config::init()` called with plugin metadata array
77+
3. `Plugin` instance created
78+
4. `plugins_loaded` hook triggers `Plugin::load()`
79+
5. `load()` sets up Container, EventManager, Options, registers Subscribers
80+
6. `do_action('wpmedia_package_template_loaded')` fired for extensibility
81+
82+
### Adding Event Subscribers
83+
Implement `SubscriberInterface` and return hooks array:
84+
```php
85+
public static function get_subscribed_events(): array {
86+
return [
87+
'init' => 'on_init_method',
88+
'save_post' => ['on_save_post', 10, 2], // priority & args
89+
];
90+
}
91+
```
92+
93+
## Suggested Packages (Optional Enhancements)
94+
95+
The template includes composer suggestions for common use cases:
96+
97+
- **`berlindb/core`**: Use for custom database tables with ORM-like interface (e.g., logs, custom data not fitting CPTs)
98+
- **`coenjacobs/mozart`**: Wrap/prefix Composer dependencies to prevent conflicts when multiple plugins use same libraries
99+
- **`woocommerce/action-scheduler`**: Add for reliable background job processing (cron alternative with failure handling)
100+
- **`wp-media/wp-mixpanel`**: Integrate Mixpanel analytics for usage tracking
101+
102+
Install via: `composer require <package>` for production, or `composer require --dev <package>` for dev dependencies.
103+
104+
## Key Files to Reference
105+
- `inc/Plugin.php`: Template for DI setup and lifecycle hooks
106+
- `Tests/Unit/TestCase.php` & `Tests/Integration/TestCase.php`: Base test classes with data loading pattern
107+
- `phpcs.xml.dist`: WordPress standards configuration with PHPCompatibility rules
108+
- `composer.json`: Available scripts and dependency versions

.github/phpcs.yml

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,15 @@
1-
name: PHP CodeSniffer lint
1+
name: PHP CodeSniffer
22

33
on:
44
pull_request:
5-
branches:
6-
- master
7-
- develop
8-
jobs:
9-
run:
10-
runs-on: ${{ matrix.operating-system }}
11-
12-
strategy:
13-
fail-fast: false
14-
matrix:
15-
operating-system: [ubuntu-latest]
16-
php-versions: ['7.4']
17-
18-
name: Lint with PHPCS. PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }}.
19-
steps:
20-
- name: Checkout
21-
uses: actions/checkout@v3
5+
# Allow manually triggering the workflow.
6+
workflow_dispatch:
227

23-
- name: Setup PHP
24-
uses: shivammathur/setup-php@v2
25-
with:
26-
php-version: ${{ matrix.php-versions }}
27-
coverage: none # XDebug can be enabled here 'coverage: xdebug'
28-
tools: composer:v2
29-
30-
- name: Install dependencies
31-
run: composer install --prefer-dist --no-interaction --no-scripts
32-
33-
- name: Lint with phpcs
34-
run: composer phpcs
8+
# Cancel all previous workflow runs for the same branch that have not yet completed.
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11+
cancel-in-progress: true
3512

13+
jobs:
14+
phpcs:
15+
uses: wp-media/workflows/.github/workflows/phpcs.yml@main

.github/phpstan.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: PHPStan
2+
3+
on:
4+
pull_request:
5+
# Allow manually triggering the workflow.
6+
workflow_dispatch:
7+
8+
# Cancel all previous workflow runs for the same branch that have not yet completed.
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
phpstan:
15+
uses: wp-media/workflows/.github/workflows/phpstan.yml@main

.github/phpunit.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: PHPUnit
2+
3+
on:
4+
pull_request:
5+
# Allow manually triggering the workflow.
6+
workflow_dispatch:
7+
8+
# Cancel all previous workflow runs for the same branch that have not yet completed.
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
run:
15+
name: PHPUnit
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Setup PHP
22+
uses: shivammathur/setup-php@v2
23+
with:
24+
php-version: '8.2'
25+
ini-values: 'memory_limit=1G'
26+
coverage: none
27+
tools: cs2pr
28+
29+
- name: Install Composer dependencies
30+
uses: "ramsey/composer-install@v3"
31+
with:
32+
# Bust the cache at least once a month - output format: YYYY-MM.
33+
custom-cache-suffix: $(date -u "+%Y-%m")
34+
35+
- name: Install SVN
36+
run: sudo apt-get install subversion
37+
38+
- name: Start mysql service
39+
run: sudo /etc/init.d/mysql start
40+
41+
- name: Install tests
42+
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:3306 latest
43+
44+
- name: Mysql8 auth plugin workaround
45+
run: sudo mysql -u root -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';"
46+
47+
- name: Run PHPUnit unit tests
48+
run: composer test-unit
49+
50+
- name: Run PHPUnit integration tests
51+
run: composer test-integration

.github/tests.yml

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)