@silverassist/agents-toolkit 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +135 -0
  2. package/README.md +388 -0
  3. package/bin/cli.js +940 -0
  4. package/package.json +52 -0
  5. package/src/index.js +58 -0
  6. package/templates/agents/AGENTS.codex.md +195 -0
  7. package/templates/agents/AGENTS.md +195 -0
  8. package/templates/agents/CLAUDE.md +213 -0
  9. package/templates/agents/copilot-instructions.md +83 -0
  10. package/templates/shared/instructions/css-styling.instructions.md +142 -0
  11. package/templates/shared/instructions/documentation-language.instructions.md +216 -0
  12. package/templates/shared/instructions/github-workflow.instructions.md +245 -0
  13. package/templates/shared/instructions/php-standards.instructions.md +293 -0
  14. package/templates/shared/instructions/react-components.instructions.md +196 -0
  15. package/templates/shared/instructions/server-actions.instructions.md +429 -0
  16. package/templates/shared/instructions/testing-standards.instructions.md +264 -0
  17. package/templates/shared/instructions/tests.instructions.md +103 -0
  18. package/templates/shared/instructions/typescript.instructions.md +106 -0
  19. package/templates/shared/instructions/wordpress-plugin-architecture.instructions.md +238 -0
  20. package/templates/shared/prompts/README.md +129 -0
  21. package/templates/shared/prompts/_partials/README.md +57 -0
  22. package/templates/shared/prompts/_partials/documentation.md +203 -0
  23. package/templates/shared/prompts/_partials/git-operations.md +171 -0
  24. package/templates/shared/prompts/_partials/github-integration.md +100 -0
  25. package/templates/shared/prompts/_partials/jira-integration.md +155 -0
  26. package/templates/shared/prompts/_partials/pr-template.md +216 -0
  27. package/templates/shared/prompts/_partials/validations.md +87 -0
  28. package/templates/shared/prompts/add-tests.prompt.md +151 -0
  29. package/templates/shared/prompts/analyze-github-issue.prompt.md +73 -0
  30. package/templates/shared/prompts/analyze-ticket.prompt.md +63 -0
  31. package/templates/shared/prompts/create-plan.prompt.md +118 -0
  32. package/templates/shared/prompts/create-pr.prompt.md +139 -0
  33. package/templates/shared/prompts/finalize-pr.prompt.md +150 -0
  34. package/templates/shared/prompts/fix-issues.prompt.md +92 -0
  35. package/templates/shared/prompts/new-wp-component.prompt.md +51 -0
  36. package/templates/shared/prompts/new-wp-plugin.prompt.md +46 -0
  37. package/templates/shared/prompts/prepare-pr.prompt.md +123 -0
  38. package/templates/shared/prompts/prepare-release.prompt.md +74 -0
  39. package/templates/shared/prompts/quality-check.prompt.md +45 -0
  40. package/templates/shared/prompts/review-code.prompt.md +81 -0
  41. package/templates/shared/prompts/work-github-issue.prompt.md +96 -0
  42. package/templates/shared/prompts/work-ticket.prompt.md +98 -0
  43. package/templates/shared/skills/README.md +53 -0
  44. package/templates/shared/skills/component-architecture/SKILL.md +321 -0
  45. package/templates/shared/skills/create-component/SKILL.md +714 -0
  46. package/templates/shared/skills/domain-driven-design/SKILL.md +277 -0
  47. package/templates/shared/skills/plugin-creation/SKILL.md +1094 -0
  48. package/templates/shared/skills/quality-checks/SKILL.md +493 -0
  49. package/templates/shared/skills/release-management/SKILL.md +649 -0
  50. package/templates/shared/skills/testing/SKILL.md +682 -0
  51. package/templates/shared/skills/testing-patterns/SKILL.md +243 -0
@@ -0,0 +1,1094 @@
1
+ ---
2
+ name: plugin-creation
3
+ description: Scaffold a new Silver Assist WordPress plugin from scratch. Covers file structure, PSR-4 autoloading, main plugin file, composer.json, LoadableInterface architecture, configuration files (phpcs.xml, phpstan.neon, phpunit.xml.dist), test bootstrap, CI/CD workflows, and AI agent customization. Use when creating a new plugin or understanding the standard architecture.
4
+ ---
5
+
6
+ # Silver Assist — Plugin Creation
7
+
8
+ This skill covers scaffolding a brand-new Silver Assist WordPress plugin from zero, following the unified standards documented in `SILVERASSIST_STANDARDS.md v2.0.0`.
9
+
10
+ ## When to Use
11
+
12
+ - Creating a new Silver Assist WordPress plugin from scratch
13
+ - Setting up the full directory structure for a plugin
14
+ - Understanding the standard plugin architecture
15
+ - Bootstrapping all configuration files (PHPCS, PHPStan, PHPUnit, CI/CD)
16
+ - Adding AI agent customization (copilot-instructions, file instructions, skills)
17
+
18
+ ## Prerequisites
19
+
20
+ - PHP 8.2+
21
+ - Composer installed globally
22
+ - WordPress 6.5+ development environment
23
+ - GitHub repository under the `SilverAssist` organization
24
+
25
+ ---
26
+
27
+ ## Architecture Overview
28
+
29
+ ### File Structure
30
+
31
+ Every Silver Assist plugin follows this structure:
32
+
33
+ ```
34
+ plugin-name/
35
+ ├── plugin-name.php # Main plugin file
36
+ ├── composer.json # Composer dependencies & autoloading
37
+ ├── README.md # User documentation
38
+ ├── CONTRIBUTING.md # Developer documentation
39
+ ├── CHANGELOG.md # Version history
40
+ ├── LICENSE # License file
41
+ ├── phpcs.xml # PHPCS configuration
42
+ ├── phpstan.neon # PHPStan configuration
43
+ ├── phpunit.xml.dist # PHPUnit configuration
44
+ ├── .github/
45
+ │ ├── copilot-instructions.md # Global AI agent context
46
+ │ ├── instructions/ # File-specific AI instructions
47
+ │ │ ├── php.instructions.md
48
+ │ │ ├── testing.instructions.md
49
+ │ │ └── ...
50
+ │ ├── skills/ # Specialized AI task skills
51
+ │ │ ├── release-management/
52
+ │ │ ├── quality-checks/
53
+ │ │ └── ...
54
+ │ └── workflows/ # CI/CD workflows
55
+ │ ├── ci.yml
56
+ │ ├── release.yml
57
+ │ ├── dependency-updates.yml
58
+ │ └── quality-checks.yml
59
+ ├── includes/ # PSR-4 classes
60
+ │ ├── Core/
61
+ │ │ ├── Plugin.php # Main plugin bootstrap (singleton)
62
+ │ │ ├── Activator.php # Activation/deactivation logic
63
+ │ │ └── Interfaces/
64
+ │ │ └── LoadableInterface.php
65
+ │ ├── Service/ # Business logic services
66
+ │ │ └── Loader.php
67
+ │ ├── Admin/ # WordPress admin integration
68
+ │ │ └── Loader.php
69
+ │ ├── Controller/ # HTTP/Admin request handlers
70
+ │ ├── View/ # HTML rendering (static classes)
71
+ │ ├── Model/ # Domain models
72
+ │ ├── Repository/ # Data access layer
73
+ │ └── Utils/ # Utility classes
74
+ │ ├── Helpers.php
75
+ │ └── Logger.php
76
+ ├── assets/
77
+ │ ├── css/
78
+ │ └── js/
79
+ ├── languages/
80
+ │ └── plugin-name.pot
81
+ ├── scripts/
82
+ │ ├── build-release.sh
83
+ │ ├── run-quality-checks.sh
84
+ │ ├── install-wp-tests.sh
85
+ │ ├── update-version-simple.sh
86
+ │ └── check-versions.sh
87
+ ├── tests/
88
+ │ ├── bootstrap.php
89
+ │ ├── README.md
90
+ │ ├── Unit/
91
+ │ ├── Integration/
92
+ │ └── Helpers/
93
+ │ ├── TestCase.php
94
+ │ └── Helpers.php
95
+ └── docs/
96
+ └── API_REFERENCE.md
97
+ ```
98
+
99
+ ### PSR-4 Autoloading
100
+
101
+ Namespace: `SilverAssist\PluginName\`
102
+
103
+ - PHP classes: `PascalCase.php` matching class names exactly
104
+ - Directories: `PascalCase/` (e.g., `Core/`, `Admin/`, `Service/`)
105
+ - Assets: `kebab-case.css`, `kebab-case.js`
106
+
107
+ ### LoadableInterface Priority System
108
+
109
+ All components implement `LoadableInterface` with three methods:
110
+ - `init()` — Initialize the component
111
+ - `get_priority()` — Loading order (lower = first)
112
+ - `should_load()` — Conditional loading
113
+
114
+ Priority values:
115
+ - **10**: Core components (Plugin, Activator, critical services)
116
+ - **20**: Services (business logic, API clients)
117
+ - **30**: Admin components (controllers, settings pages)
118
+ - **40**: Utils & Assets (helpers, loggers)
119
+
120
+ ---
121
+
122
+ ## Step-by-Step Plugin Creation
123
+
124
+ ### Step 1: Create Directory and Initialize Composer
125
+
126
+ ```bash
127
+ mkdir plugin-name && cd plugin-name
128
+ ```
129
+
130
+ Create `composer.json`:
131
+
132
+ ```json
133
+ {
134
+ "name": "silverassist/plugin-slug",
135
+ "description": "WordPress plugin description",
136
+ "type": "wordpress-plugin",
137
+ "license": "PolyForm-Noncommercial-1.0.0",
138
+ "authors": [
139
+ {
140
+ "name": "Silver Assist",
141
+ "homepage": "https://silverassist.com/"
142
+ }
143
+ ],
144
+ "minimum-stability": "stable",
145
+ "require": {
146
+ "php": ">=8.2",
147
+ "composer/installers": "^2.0",
148
+ "silverassist/wp-github-updater": "^1.1",
149
+ "silverassist/wp-settings-hub": "^1.0"
150
+ },
151
+ "require-dev": {
152
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
153
+ "php-stubs/wordpress-stubs": "^6.6",
154
+ "php-stubs/wordpress-tests-stubs": "^6.6",
155
+ "phpcompatibility/phpcompatibility-wp": "^2.1",
156
+ "phpstan/phpstan": "*",
157
+ "phpunit/phpunit": "^9.6",
158
+ "squizlabs/php_codesniffer": "^3.7 || ^4.0",
159
+ "szepeviktor/phpstan-wordpress": "^1.3 || ^2.0",
160
+ "wp-coding-standards/wpcs": "^3.0",
161
+ "yoast/phpunit-polyfills": "^4.0"
162
+ },
163
+ "autoload": {
164
+ "psr-4": {
165
+ "SilverAssist\\PluginName\\": "includes/"
166
+ }
167
+ },
168
+ "autoload-dev": {
169
+ "psr-4": {
170
+ "SilverAssist\\PluginName\\Tests\\": "tests/"
171
+ }
172
+ },
173
+ "scripts": {
174
+ "phpcs": "phpcs",
175
+ "phpcbf": "phpcbf",
176
+ "phpstan": "phpstan analyse --memory-limit=1G",
177
+ "phpunit": "phpunit",
178
+ "test": [
179
+ "@phpcs",
180
+ "@phpstan",
181
+ "@phpunit"
182
+ ]
183
+ },
184
+ "config": {
185
+ "allow-plugins": {
186
+ "composer/installers": true,
187
+ "dealerdirect/phpcodesniffer-composer-installer": true
188
+ }
189
+ }
190
+ }
191
+ ```
192
+
193
+ Then run:
194
+
195
+ ```bash
196
+ composer install
197
+ ```
198
+
199
+ ### Step 2: Create Main Plugin File
200
+
201
+ File: `plugin-name.php`
202
+
203
+ **CRITICAL**: Must include `Update URI` header to prevent WordPress.org update conflicts.
204
+
205
+ ```php
206
+ <?php
207
+ /**
208
+ * Plugin Name: Plugin Display Name
209
+ * Plugin URI: https://github.com/SilverAssist/plugin-slug
210
+ * Description: Brief plugin description.
211
+ * Version: 1.0.0
212
+ * Author: Silver Assist
213
+ * Author URI: https://silverassist.com
214
+ * License: PolyForm-Noncommercial-1.0.0
215
+ * License URI: https://polyformproject.org/licenses/noncommercial/1.0.0/
216
+ * Text Domain: plugin-text-domain
217
+ * Domain Path: /languages
218
+ * Requires at least: 6.5
219
+ * Tested up to: 6.8
220
+ * Requires PHP: 8.2
221
+ * Network: false
222
+ * Update URI: https://github.com/SilverAssist/plugin-slug
223
+ *
224
+ * @package SilverAssist\PluginName
225
+ * @author Silver Assist
226
+ * @license PolyForm-Noncommercial-1.0.0
227
+ * @since 1.0.0
228
+ */
229
+
230
+ // Prevent direct access.
231
+ \defined( 'ABSPATH' ) || exit;
232
+
233
+ // Define plugin constants.
234
+ define( 'PLUGIN_PREFIX_VERSION', '1.0.0' );
235
+ define( 'PLUGIN_PREFIX_FILE', __FILE__ );
236
+ define( 'PLUGIN_PREFIX_PATH', plugin_dir_path( __FILE__ ) );
237
+ define( 'PLUGIN_PREFIX_BASENAME', plugin_basename( __FILE__ ) );
238
+
239
+ /**
240
+ * Composer autoloader with security validation.
241
+ */
242
+ $plugin_prefix_autoload_path = PLUGIN_PREFIX_PATH . 'vendor/autoload.php';
243
+ $plugin_prefix_real_autoload_path = realpath( $plugin_prefix_autoload_path );
244
+ $plugin_prefix_plugin_real_path = realpath( PLUGIN_PREFIX_PATH );
245
+
246
+ // Validate: both paths resolve, autoloader is inside plugin directory.
247
+ if (
248
+ $plugin_prefix_real_autoload_path &&
249
+ $plugin_prefix_plugin_real_path &&
250
+ 0 === strpos( $plugin_prefix_real_autoload_path, $plugin_prefix_plugin_real_path )
251
+ ) {
252
+ require_once $plugin_prefix_real_autoload_path;
253
+ } else {
254
+ add_action(
255
+ 'admin_notices',
256
+ function () {
257
+ printf(
258
+ '<div class="notice notice-error"><p>%s</p></div>',
259
+ esc_html__( 'Plugin Name: Missing or invalid Composer dependencies. Run "composer install".', 'plugin-text-domain' )
260
+ );
261
+ }
262
+ );
263
+ return;
264
+ }
265
+
266
+ // Initialize plugin.
267
+ add_action(
268
+ 'plugins_loaded',
269
+ function () {
270
+ \SilverAssist\PluginName\Core\Plugin::instance()->init();
271
+ }
272
+ );
273
+
274
+ // Register activation hook.
275
+ register_activation_hook(
276
+ __FILE__,
277
+ function () {
278
+ \SilverAssist\PluginName\Core\Activator::activate();
279
+ }
280
+ );
281
+ ```
282
+
283
+ **Key Elements:**
284
+ - Prefixed global variables (`$plugin_prefix_*`) for WPCS compliance
285
+ - Security validation for Composer autoloader path (prevents path traversal)
286
+ - Graceful degradation with admin notice if autoloader missing
287
+ - Hook registration via closures
288
+
289
+ ### Step 3: Create Core Classes
290
+
291
+ #### LoadableInterface
292
+
293
+ File: `includes/Core/Interfaces/LoadableInterface.php`
294
+
295
+ ```php
296
+ <?php
297
+ namespace SilverAssist\PluginName\Core\Interfaces;
298
+
299
+ /**
300
+ * LoadableInterface defines the contract for loadable components.
301
+ *
302
+ * @package SilverAssist\PluginName\Core\Interfaces
303
+ */
304
+ interface LoadableInterface {
305
+ /**
306
+ * Initialize the component.
307
+ *
308
+ * @return void
309
+ */
310
+ public function init(): void;
311
+
312
+ /**
313
+ * Get the loading priority.
314
+ *
315
+ * Lower numbers = higher priority.
316
+ * - 10: Core components
317
+ * - 20: Services
318
+ * - 30: Admin components
319
+ * - 40: Utils & Assets
320
+ *
321
+ * @return int
322
+ */
323
+ public function get_priority(): int;
324
+
325
+ /**
326
+ * Check if component should load.
327
+ *
328
+ * @return bool
329
+ */
330
+ public function should_load(): bool;
331
+ }
332
+ ```
333
+
334
+ #### Plugin.php (Main Bootstrap)
335
+
336
+ File: `includes/Core/Plugin.php`
337
+
338
+ ```php
339
+ <?php
340
+ namespace SilverAssist\PluginName\Core;
341
+
342
+ use SilverAssist\PluginName\Core\Interfaces\LoadableInterface;
343
+
344
+ /**
345
+ * Main Plugin Class.
346
+ *
347
+ * @package SilverAssist\PluginName\Core
348
+ * @since 1.0.0
349
+ */
350
+ class Plugin implements LoadableInterface {
351
+ /**
352
+ * Plugin instance.
353
+ *
354
+ * @var Plugin|null
355
+ */
356
+ private static ?Plugin $instance = null;
357
+
358
+ /**
359
+ * Initialization flag.
360
+ *
361
+ * @var bool
362
+ */
363
+ private bool $initialized = false;
364
+
365
+ /**
366
+ * Get plugin instance.
367
+ *
368
+ * @return Plugin
369
+ */
370
+ public static function instance(): Plugin {
371
+ if ( self::$instance === null ) {
372
+ self::$instance = new self();
373
+ }
374
+ return self::$instance;
375
+ }
376
+
377
+ /**
378
+ * Private constructor to prevent direct instantiation.
379
+ */
380
+ private function __construct() {
381
+ // Initialization logic.
382
+ }
383
+
384
+ /**
385
+ * Initialize plugin.
386
+ *
387
+ * @return void
388
+ */
389
+ public function init(): void {
390
+ if ( $this->initialized ) {
391
+ return;
392
+ }
393
+
394
+ $this->load_components();
395
+ $this->init_hooks();
396
+
397
+ $this->initialized = true;
398
+ }
399
+
400
+ /**
401
+ * Get loading priority.
402
+ *
403
+ * @return int
404
+ */
405
+ public function get_priority(): int {
406
+ return 10;
407
+ }
408
+
409
+ /**
410
+ * Should this component load?
411
+ *
412
+ * @return bool
413
+ */
414
+ public function should_load(): bool {
415
+ return true;
416
+ }
417
+
418
+ /**
419
+ * Get components to load.
420
+ *
421
+ * @return array<class-string<LoadableInterface>>
422
+ */
423
+ private function get_components(): array {
424
+ return [
425
+ // Add component classes here.
426
+ // \SilverAssist\PluginName\Service\ServiceName::class,
427
+ // \SilverAssist\PluginName\Admin\Settings::class,
428
+ ];
429
+ }
430
+
431
+ /**
432
+ * Load all components by priority.
433
+ *
434
+ * @return void
435
+ */
436
+ private function load_components(): void {
437
+ $components = [];
438
+
439
+ foreach ( $this->get_components() as $class ) {
440
+ if ( method_exists( $class, 'instance' ) ) {
441
+ $instance = $class::instance();
442
+ if ( $instance->should_load() ) {
443
+ $components[] = $instance;
444
+ }
445
+ }
446
+ }
447
+
448
+ // Sort by priority (lower first).
449
+ usort( $components, fn( $a, $b ) => $a->get_priority() <=> $b->get_priority() );
450
+
451
+ // Initialize all.
452
+ foreach ( $components as $component ) {
453
+ $component->init();
454
+ }
455
+ }
456
+
457
+ /**
458
+ * Initialize plugin hooks.
459
+ *
460
+ * @return void
461
+ */
462
+ private function init_hooks(): void {
463
+ $this->init_updater();
464
+ }
465
+
466
+ /**
467
+ * Initialize GitHub updater.
468
+ *
469
+ * @return void
470
+ */
471
+ private function init_updater(): void {
472
+ if ( ! class_exists( \SilverAssist\GitHubUpdater\UpdaterConfig::class ) ) {
473
+ return;
474
+ }
475
+
476
+ $config = new \SilverAssist\GitHubUpdater\UpdaterConfig(
477
+ plugin_basename: PLUGIN_PREFIX_BASENAME,
478
+ version: PLUGIN_PREFIX_VERSION,
479
+ github_repo: 'SilverAssist/plugin-slug',
480
+ plugin_file: PLUGIN_PREFIX_FILE
481
+ );
482
+
483
+ $config->init();
484
+ }
485
+ }
486
+ ```
487
+
488
+ #### Activator.php
489
+
490
+ File: `includes/Core/Activator.php`
491
+
492
+ ```php
493
+ <?php
494
+ namespace SilverAssist\PluginName\Core;
495
+
496
+ /**
497
+ * Plugin Activator.
498
+ *
499
+ * @package SilverAssist\PluginName\Core
500
+ * @since 1.0.0
501
+ */
502
+ class Activator {
503
+ /**
504
+ * Plugin activation logic.
505
+ *
506
+ * @return void
507
+ */
508
+ public static function activate(): void {
509
+ // Create database tables.
510
+ // self::create_tables();
511
+
512
+ // Set default options.
513
+ self::set_default_options();
514
+
515
+ // Flush rewrite rules.
516
+ \flush_rewrite_rules();
517
+ }
518
+
519
+ /**
520
+ * Plugin deactivation logic.
521
+ *
522
+ * @return void
523
+ */
524
+ public static function deactivate(): void {
525
+ // Clean up temporary data.
526
+ \flush_rewrite_rules();
527
+ }
528
+
529
+ /**
530
+ * Set default options.
531
+ *
532
+ * @return void
533
+ */
534
+ private static function set_default_options(): void {
535
+ if ( ! \get_option( 'plugin_prefix_settings' ) ) {
536
+ \update_option( 'plugin_prefix_settings', [
537
+ 'enabled' => true,
538
+ ] );
539
+ }
540
+ }
541
+ }
542
+ ```
543
+
544
+ ### Step 4: Create Configuration Files
545
+
546
+ #### phpcs.xml
547
+
548
+ ```xml
549
+ <?xml version="1.0"?>
550
+ <ruleset name="SilverAssist Plugin Standards">
551
+ <description>WordPress Coding Standards for SilverAssist Plugins</description>
552
+
553
+ <file>.</file>
554
+
555
+ <exclude-pattern>*/vendor/*</exclude-pattern>
556
+ <exclude-pattern>*/node_modules/*</exclude-pattern>
557
+ <exclude-pattern>*/.git/*</exclude-pattern>
558
+ <exclude-pattern>*/tests/*</exclude-pattern>
559
+ <exclude-pattern>*/build/*</exclude-pattern>
560
+ <exclude-pattern>*/assets/js/*</exclude-pattern>
561
+ <exclude-pattern>*/assets/css/*</exclude-pattern>
562
+
563
+ <arg value="ps"/>
564
+ <arg name="colors"/>
565
+
566
+ <config name="testVersion" value="8.2-"/>
567
+
568
+ <rule ref="WordPress-Extra">
569
+ <exclude name="Generic.Arrays.DisallowShortArraySyntax"/>
570
+ <exclude name="WordPress.Files.FileName.NotHyphenatedLowercase"/>
571
+ <exclude name="WordPress.Files.FileName.InvalidClassFileName"/>
572
+ <exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie"/>
573
+ <exclude name="Generic.Classes.OpeningBraceSameLine"/>
574
+ </rule>
575
+
576
+ <rule ref="Universal.Arrays.DisallowShortArraySyntax">
577
+ <exclude name="Universal.Arrays.DisallowShortArraySyntax.Found"/>
578
+ </rule>
579
+
580
+ <rule ref="WordPress.NamingConventions.PrefixAllGlobals">
581
+ <properties>
582
+ <property name="prefixes" type="array">
583
+ <element value="plugin_prefix"/>
584
+ <element value="SilverAssist\PluginName"/>
585
+ </property>
586
+ </properties>
587
+ </rule>
588
+
589
+ <rule ref="WordPress-Docs"/>
590
+ <rule ref="Generic.CodeAnalysis.UnusedFunctionParameter"/>
591
+ <rule ref="Generic.Commenting.Todo"/>
592
+
593
+ <config name="minimum_supported_wp_version" value="6.5"/>
594
+ </ruleset>
595
+ ```
596
+
597
+ **IMPORTANT**: Replace `plugin_prefix` and `SilverAssist\PluginName` with the actual plugin prefix and namespace.
598
+
599
+ #### phpstan.neon
600
+
601
+ ```yaml
602
+ includes:
603
+ - vendor/szepeviktor/phpstan-wordpress/extension.neon
604
+
605
+ parameters:
606
+ level: 8
607
+ paths:
608
+ - includes
609
+ bootstrapFiles:
610
+ - plugin-main-file.php
611
+ scanDirectories:
612
+ - vendor
613
+ excludePaths:
614
+ - tests/*
615
+ - build/*
616
+ ```
617
+
618
+ **IMPORTANT**: Replace `plugin-main-file.php` with the actual main plugin filename.
619
+
620
+ #### phpunit.xml.dist
621
+
622
+ ```xml
623
+ <?xml version="1.0" encoding="UTF-8"?>
624
+ <phpunit
625
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
626
+ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd"
627
+ bootstrap="tests/bootstrap.php"
628
+ colors="true"
629
+ verbose="true"
630
+ stopOnFailure="false"
631
+ stopOnError="false"
632
+ beStrictAboutOutputDuringTests="true"
633
+ beStrictAboutTodoAnnotatedTests="true">
634
+
635
+ <testsuites>
636
+ <testsuite name="unit">
637
+ <directory suffix="Test.php">./tests/Unit</directory>
638
+ </testsuite>
639
+ <testsuite name="integration">
640
+ <directory suffix="Test.php">./tests/Integration</directory>
641
+ </testsuite>
642
+ <testsuite name="all">
643
+ <directory suffix="Test.php">./tests/Unit</directory>
644
+ <directory suffix="Test.php">./tests/Integration</directory>
645
+ </testsuite>
646
+ </testsuites>
647
+
648
+ <groups>
649
+ <exclude>
650
+ <group>ajax</group>
651
+ <group>ms-files</group>
652
+ <group>external-http</group>
653
+ </exclude>
654
+ </groups>
655
+
656
+ <coverage processUncoveredFiles="true">
657
+ <include>
658
+ <directory suffix=".php">./includes</directory>
659
+ </include>
660
+ <exclude>
661
+ <directory>./vendor</directory>
662
+ <directory>./tests</directory>
663
+ </exclude>
664
+ </coverage>
665
+
666
+ <php>
667
+ <env name="WP_ENVIRONMENT_TYPE" value="test"/>
668
+ <env name="WP_DEBUG" value="true"/>
669
+ <env name="WP_DEBUG_LOG" value="false"/>
670
+ <env name="WP_DEBUG_DISPLAY" value="false"/>
671
+ <env name="SCRIPT_DEBUG" value="false"/>
672
+ <const name="WP_TESTS_PHPUNIT_POLYFILLS_PATH" value="vendor/yoast/phpunit-polyfills"/>
673
+ <const name="PLUGIN_PREFIX_TESTING" value="true"/>
674
+ </php>
675
+ </phpunit>
676
+ ```
677
+
678
+ ### Step 5: Create Test Infrastructure
679
+
680
+ See the **testing** skill for full details on `tests/bootstrap.php`, `tests/Helpers/TestCase.php`, and test patterns.
681
+
682
+ ### Step 6: Create CI/CD Workflows
683
+
684
+ See the **release-management** skill for `release.yml` and the CI workflow templates.
685
+
686
+ #### ci.yml
687
+
688
+ File: `.github/workflows/ci.yml`
689
+
690
+ ```yaml
691
+ name: CI
692
+ permissions:
693
+ contents: read
694
+
695
+ on:
696
+ push:
697
+ branches: [ main, develop ]
698
+ pull_request:
699
+ branches: [ main ]
700
+ workflow_dispatch:
701
+
702
+ jobs:
703
+ quality-checks-82:
704
+ name: Quality Checks (PHP 8.2)
705
+ uses: ./.github/workflows/quality-checks.yml
706
+ with:
707
+ php-version: '8.2'
708
+ skip-wp-setup: false
709
+ upload-coverage: true
710
+
711
+ quality-checks-83:
712
+ name: Quality Checks (PHP 8.3)
713
+ uses: ./.github/workflows/quality-checks.yml
714
+ with:
715
+ php-version: '8.3'
716
+ skip-wp-setup: false
717
+ upload-coverage: false
718
+
719
+ quality-checks-84:
720
+ name: Quality Checks (PHP 8.4)
721
+ uses: ./.github/workflows/quality-checks.yml
722
+ with:
723
+ php-version: '8.4'
724
+ skip-wp-setup: false
725
+ upload-coverage: false
726
+
727
+ security-scan:
728
+ name: Security Scan
729
+ runs-on: ubuntu-latest
730
+ steps:
731
+ - uses: actions/checkout@v5
732
+ - uses: shivammathur/setup-php@v2
733
+ with:
734
+ php-version: '8.2'
735
+ extensions: mbstring, intl
736
+ coverage: none
737
+ - run: composer install --no-interaction --no-progress --optimize-autoloader
738
+ - run: composer audit
739
+
740
+ compatibility:
741
+ name: WordPress Compatibility
742
+ runs-on: ubuntu-latest
743
+ strategy:
744
+ matrix:
745
+ wordpress-version: ['6.5', '6.6', '6.7', 'latest']
746
+ services:
747
+ mysql:
748
+ image: mysql:8.0
749
+ env:
750
+ MYSQL_ROOT_PASSWORD: root
751
+ MYSQL_DATABASE: wordpress_test
752
+ ports:
753
+ - 3306:3306
754
+ options: >-
755
+ --health-cmd="mysqladmin ping"
756
+ --health-interval=10s
757
+ --health-timeout=5s
758
+ --health-retries=5
759
+ steps:
760
+ - uses: actions/checkout@v5
761
+ - uses: shivammathur/setup-php@v2
762
+ with:
763
+ php-version: '8.2'
764
+ extensions: mbstring, intl, mysql, pdo_mysql
765
+ coverage: none
766
+ - run: composer install --no-interaction --no-progress --optimize-autoloader
767
+ - run: bash scripts/install-wp-tests.sh wordpress_test root 'root' 127.0.0.1 ${{ matrix.wordpress-version }} false
768
+ - run: vendor/bin/phpunit
769
+ ```
770
+
771
+ ### Step 7: Create .gitignore
772
+
773
+ ```gitignore
774
+ # Dependencies
775
+ vendor/
776
+ node_modules/
777
+ composer.lock
778
+
779
+ # Build
780
+ build/
781
+ dist/
782
+ *.zip
783
+ *.tar.gz
784
+
785
+ # IDE
786
+ .idea/
787
+ .vscode/
788
+ *.swp
789
+ *.swo
790
+
791
+ # OS
792
+ .DS_Store
793
+ Thumbs.db
794
+
795
+ # Coverage
796
+ coverage/
797
+ .phpunit.result.cache
798
+ ```
799
+
800
+ ### Step 8: Create CHANGELOG.md
801
+
802
+ ```markdown
803
+ # Changelog
804
+
805
+ All notable changes to Plugin Name will be documented in this file.
806
+
807
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
808
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
809
+
810
+ ## [Unreleased]
811
+
812
+ ## [1.0.0] - YYYY-MM-DD
813
+
814
+ ### Added
815
+ - Initial release.
816
+ ```
817
+
818
+ ---
819
+
820
+ ## PHP Requirements & Coding Standards
821
+
822
+ ### PHP Version
823
+ - **Minimum**: PHP 8.2
824
+ - **Recommended**: PHP 8.3+
825
+ - Use modern PHP: enums, readonly properties, union types, named arguments
826
+
827
+ ### WordPress Naming Conventions (CRITICAL for WPCS)
828
+
829
+ 1. **Global variables**: Prefix with `plugin_prefix_`
830
+ 2. **Functions**: Prefix with `plugin_prefix_`
831
+ 3. **Constants**: Prefix with `PLUGIN_PREFIX_`
832
+ 4. **Classes**: Namespaced (no prefix needed)
833
+ 5. **Inline comments**: MUST end with `.`, `!`, or `?`
834
+ 6. **WordPress functions in namespaced code**: MUST use backslash prefix (`\add_action()`, `\get_option()`)
835
+ 7. **String quotation**: Single quotes for literals, double quotes only for interpolation
836
+
837
+ ### Security Standards
838
+
839
+ **Input Sanitization:**
840
+ ```php
841
+ $text = \sanitize_text_field( \wp_unslash( $_POST['field_name'] ) );
842
+ $email = \sanitize_email( $_POST['email'] );
843
+ $url = \esc_url_raw( $_POST['url'] );
844
+ $int = \absint( $_POST['number'] );
845
+ ```
846
+
847
+ **Output Escaping:**
848
+ ```php
849
+ echo \esc_html( $text );
850
+ echo '<div class="' . \esc_attr( $class ) . '">';
851
+ echo '<a href="' . \esc_url( $url ) . '">';
852
+ ```
853
+
854
+ **Nonce Verification:**
855
+ ```php
856
+ \wp_nonce_field( 'plugin_action', 'plugin_nonce' );
857
+ if ( ! isset( $_POST['plugin_nonce'] ) || ! \wp_verify_nonce( $_POST['plugin_nonce'], 'plugin_action' ) ) {
858
+ \wp_die( \esc_html__( 'Security check failed.', 'plugin-text-domain' ) );
859
+ }
860
+ ```
861
+
862
+ **Capability Checks:**
863
+ ```php
864
+ if ( ! \current_user_can( 'manage_options' ) ) {
865
+ \wp_die( \esc_html__( 'Insufficient permissions.', 'plugin-text-domain' ) );
866
+ }
867
+ ```
868
+
869
+ ### Database Operations
870
+
871
+ Use `%i` placeholder for table/column names (WordPress 6.2+):
872
+
873
+ ```php
874
+ $results = $wpdb->get_results(
875
+ $wpdb->prepare(
876
+ 'SELECT * FROM %i WHERE status = %s AND form_id = %d',
877
+ $table_name,
878
+ $status,
879
+ $form_id
880
+ ),
881
+ ARRAY_A
882
+ );
883
+ ```
884
+
885
+ | Placeholder | Use Case |
886
+ |-------------|----------|
887
+ | `%i` | Identifiers (table/column names) |
888
+ | `%s` | Strings |
889
+ | `%d` | Integers |
890
+ | `%f` | Floats |
891
+
892
+ ### Documentation (PHPDoc)
893
+
894
+ All classes, methods, and properties MUST have PHPDoc:
895
+
896
+ ```php
897
+ /**
898
+ * Class description.
899
+ *
900
+ * @package SilverAssist\PluginName
901
+ * @since 1.0.0
902
+ */
903
+ class ClassName {
904
+ /**
905
+ * Property description.
906
+ *
907
+ * @var string
908
+ */
909
+ private string $property;
910
+
911
+ /**
912
+ * Method description.
913
+ *
914
+ * @param string $param Parameter description.
915
+ * @return bool Return value description.
916
+ * @since 1.0.0
917
+ */
918
+ public function method_name( string $param ): bool {
919
+ // Implementation.
920
+ return true;
921
+ }
922
+ }
923
+ ```
924
+
925
+ ### Internationalization (i18n)
926
+
927
+ **Pre-PR**: Always regenerate `.pot`:
928
+
929
+ ```bash
930
+ wp i18n make-pot . languages/plugin-text-domain.pot --domain=plugin-text-domain
931
+ ```
932
+
933
+ **Rules:**
934
+ - ALWAYS use literal text domain strings (never variables/constants)
935
+ - ALWAYS use ordered placeholders for multiple args with translator comments
936
+
937
+ ```php
938
+ sprintf(
939
+ /* translators: %1$s: form name, %2$d: submission count */
940
+ __( 'Form "%1$s" has %2$d submissions', 'plugin-text-domain' ),
941
+ $form_name,
942
+ $count
943
+ );
944
+ ```
945
+
946
+ ---
947
+
948
+ ## SilverAssist Required Packages
949
+
950
+ ### wp-github-updater
951
+
952
+ Enables automatic updates from GitHub releases.
953
+
954
+ ```bash
955
+ composer require silverassist/wp-github-updater:^1.1
956
+ ```
957
+
958
+ Integration via `UpdaterConfig` in `Plugin::init_updater()` (see Plugin.php template above).
959
+
960
+ **IMPORTANT**: Do NOT add update-related headers to plugin file (handled programmatically by the package).
961
+
962
+ ### wp-settings-hub
963
+
964
+ Provides unified settings interface for all SilverAssist plugins.
965
+
966
+ ```bash
967
+ composer require silverassist/wp-settings-hub:^1.0
968
+ ```
969
+
970
+ Integration in Settings class:
971
+
972
+ ```php
973
+ use SilverAssist\SettingsHub\SettingsHub;
974
+
975
+ public function register_settings_page(): void {
976
+ if ( ! class_exists( SettingsHub::class ) ) {
977
+ // Fallback: standalone settings page.
978
+ \add_options_page( ... );
979
+ return;
980
+ }
981
+
982
+ SettingsHub::get_instance()->register_plugin_page(
983
+ slug: 'plugin-settings',
984
+ title: __( 'Plugin Name', 'plugin-text-domain' ),
985
+ callback: [ $this, 'render_settings_page' ],
986
+ icon: 'dashicons-admin-generic',
987
+ position: 10
988
+ );
989
+ }
990
+ ```
991
+
992
+ **Note**: Settings Hub uses `get_instance()` (different from plugin singletons which use `instance()`).
993
+
994
+ ---
995
+
996
+ ## View Classes (No LoadableInterface)
997
+
998
+ Views are static classes for HTML rendering — they do NOT implement LoadableInterface:
999
+
1000
+ ```php
1001
+ <?php
1002
+ namespace SilverAssist\PluginName\View\Admin;
1003
+
1004
+ \defined( 'ABSPATH' ) || exit;
1005
+
1006
+ /**
1007
+ * Settings page view.
1008
+ *
1009
+ * @package SilverAssist\PluginName\View\Admin
1010
+ */
1011
+ class SettingsView {
1012
+ /**
1013
+ * Render the settings page.
1014
+ *
1015
+ * @param array<string, mixed> $data Data to render.
1016
+ * @return void
1017
+ */
1018
+ public static function render( array $data ): void {
1019
+ ?>
1020
+ <div class="wrap">
1021
+ <h1><?php \esc_html_e( 'Settings', 'plugin-text-domain' ); ?></h1>
1022
+ <!-- HTML content -->
1023
+ </div>
1024
+ <?php
1025
+ }
1026
+ }
1027
+ ```
1028
+
1029
+ ---
1030
+
1031
+ ## AI Agent Customization (VS Code)
1032
+
1033
+ ### 3-Tier System
1034
+
1035
+ | Level | Location | Scope |
1036
+ |-------|----------|-------|
1037
+ | Global Context | `.github/copilot-instructions.md` | Always active |
1038
+ | File-Specific | `.github/instructions/*.instructions.md` | Conditional via `applyTo` |
1039
+ | Task Skills | `.github/skills/*/SKILL.md` | On-demand |
1040
+
1041
+ ### copilot-instructions.md Template
1042
+
1043
+ Keep concise (~100-150 lines max). Move details to Instructions or Skills.
1044
+
1045
+ Should contain:
1046
+ - Project overview (name, namespace, PHP version, WP version, standards)
1047
+ - Architecture summary (LoadableInterface priorities, key directories)
1048
+ - Critical rules (pre-PR checklist commands)
1049
+ - Quick references (common commands)
1050
+
1051
+ ### Recommended Instructions Files
1052
+
1053
+ | File | `applyTo` | Content |
1054
+ |------|-----------|---------|
1055
+ | `php.instructions.md` | `**/*.php` | PHPCS rules, security, architecture |
1056
+ | `testing.instructions.md` | `tests/**/*.php` | Test patterns, WP factories |
1057
+ | `github-workflow.instructions.md` | `.github/workflows/**` | CI/CD patterns |
1058
+ | `documentation-language.instructions.md` | `**/*.md` | Language rules for docs |
1059
+
1060
+ ### Recommended Skills
1061
+
1062
+ | Skill | Description |
1063
+ |-------|-------------|
1064
+ | `release-management` | Version bumps, immutable tags, release workflow |
1065
+ | `quality-checks` | PHPCS, PHPStan, PHPUnit troubleshooting |
1066
+ | `create-component` | New services, controllers, views with LoadableInterface |
1067
+
1068
+ ---
1069
+
1070
+ ## Checklist for New Plugin
1071
+
1072
+ - [ ] Directory created with correct slug
1073
+ - [ ] `composer.json` with correct namespace, prefixes, and packages
1074
+ - [ ] Main plugin file with all required headers (including `Update URI`)
1075
+ - [ ] `includes/Core/Interfaces/LoadableInterface.php` created
1076
+ - [ ] `includes/Core/Plugin.php` with singleton, components, and updater
1077
+ - [ ] `includes/Core/Activator.php` with activate/deactivate methods
1078
+ - [ ] `phpcs.xml` with correct prefixes for the plugin
1079
+ - [ ] `phpstan.neon` with correct bootstrap file
1080
+ - [ ] `phpunit.xml.dist` with correct constant prefix
1081
+ - [ ] `tests/bootstrap.php` with correct constants and plugin file
1082
+ - [ ] `tests/Helpers/TestCase.php` extending `WP_UnitTestCase`
1083
+ - [ ] `.github/workflows/ci.yml` created
1084
+ - [ ] `.github/workflows/release.yml` created (see release-management skill)
1085
+ - [ ] `scripts/build-release.sh` copied from existing plugin
1086
+ - [ ] `scripts/update-version-simple.sh` created
1087
+ - [ ] `.gitignore` configured
1088
+ - [ ] `CHANGELOG.md` initialized
1089
+ - [ ] `README.md` created
1090
+ - [ ] `LICENSE` file added (PolyForm-Noncommercial-1.0.0)
1091
+ - [ ] `composer install` runs successfully
1092
+ - [ ] `vendor/bin/phpcs` passes with 0 errors
1093
+ - [ ] `vendor/bin/phpstan analyse` passes at level 8
1094
+ - [ ] GitHub repository created under SilverAssist organization