Skip to content
Closed
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
72b4e56
Build admin settings screen
Nov 2, 2025
013f8e7
Add test coverage for Example_Feature register and render methods
Nov 2, 2025
379e44f
Refactor React components into separate files
Nov 2, 2025
0fc0a70
Include build directory for plugin activation
Nov 2, 2025
7774324
Enable JavaScript linting in test workflow
Nov 2, 2025
a7eacdc
Format code with Prettier
Nov 2, 2025
bfc6154
Revert "Format code with Prettier"
Nov 2, 2025
0194419
Stop tracking build output
Nov 2, 2025
08f883c
Disable JS lint workflow again
Nov 2, 2025
89394cc
Remove generated ai.zip
Nov 2, 2025
876955d
Fix JS lint violations
Nov 2, 2025
cf77782
Restore bootstrap baseline
Nov 2, 2025
db48a13
Re-enable JS lint workflow
Nov 2, 2025
b6740e2
Fix plugin path constants for assets
Nov 2, 2025
6922346
Document admin settings architecture
Nov 2, 2025
cf7fc73
Restore footer illustration in developer guide
Nov 2, 2025
3035c5f
Resolve developer guide footer conflict
Nov 2, 2025
f11fdf4
Merge branch 'trunk' into feature/admin-settings-screen-issue-25
Ref34t Nov 2, 2025
20441b0
Silence phpstan require warning
Nov 3, 2025
2aca4bb
Refactor admin asset loader
Nov 3, 2025
87c57b3
Pass toggles service to default feature filter
Nov 3, 2025
48b2b28
Include build directory in package files
Nov 3, 2025
d2cc9a5
Build bundle before packaging
Nov 3, 2025
bedc00a
Fallback to Playground comment when body update fails
Nov 3, 2025
092ee3b
Guard Playground automation for upstream PRs
Nov 3, 2025
3bd52bf
Revert Playground automation guard
Nov 3, 2025
0d6537b
Re-run Playground workflow for testing
Nov 3, 2025
b6155d5
Restore Playground PR comment fallback
Nov 9, 2025
ce9c0d0
Refactor feature lifecycle and admin UI structure
Nov 9, 2025
b40d86b
Use abstract default-enabled hook directly
Nov 9, 2025
e799aae
Fix coding standard warnings
Nov 9, 2025
33fe657
Refresh developer guide for new structure
Nov 9, 2025
af8ef99
Align assignments per coding standards
Nov 9, 2025
dd1c67f
Tidy alignment per WPCS
Nov 9, 2025
1b1afb8
Fix indentation in feature toggle resolver
Nov 9, 2025
9d3121a
Normalize trait assignment alignment
Nov 9, 2025
d5e2afc
DRY admin settings page title
Nov 9, 2025
b9c502c
Keep notice visible during repeat toggles
Nov 9, 2025
fbe3665
Pin notice placeholder to prevent layout jump
Nov 9, 2025
57ee557
Prevent settings card jump when spinner shows
Nov 9, 2025
52a83e7
Align global toggle layout with feature cards
Nov 9, 2025
b7e6e43
Remove redundant helper copy
Nov 9, 2025
716750e
Decouple global vs feature saving state
Nov 9, 2025
77b7d22
Drop unused helper card body
Nov 9, 2025
d42255b
Add breathing room above global toggle card
Nov 9, 2025
229ed80
Keep feature cards rendered regardless of master toggle
Nov 9, 2025
ba48de1
Use WP_AI_DIR for style file path
Nov 9, 2025
8f44aad
Refine Asset_Loader includes
Nov 9, 2025
092d239
Import Asset_Loader in settings assets
Nov 9, 2025
6a56e7e
Use FQCN for Asset_Loader calls
Nov 9, 2025
3784468
Remove unused CardDivider import
Nov 9, 2025
16ab9e0
Align asset loader with shared implementation
Nov 9, 2025
5e0f0da
Provide helper for admin page title translation
Nov 9, 2025
b9714ee
Stabilize header spinner and fix alignment
Nov 9, 2025
4d40ed4
Remove global toggle spinner
Nov 9, 2025
07bbc1c
Clarify admin layout in developer guide
Nov 9, 2025
8702a48
Streamline admin settings stack
Nov 14, 2025
1778157
Trim developer guide instructions
Nov 14, 2025
3516583
Remove key design principles section
Nov 14, 2025
f165518
Merge branch 'upstream-trunk' into feature/admin-settings-screen-issu…
Nov 14, 2025
ad438dd
Fix Title_Generation feature to match Abstract_Feature architecture
Nov 14, 2025
f7e911b
Fix lint config and tests
Nov 14, 2025
0c6a86d
Implement test feature hooks
Nov 14, 2025
8c57baf
Add settings section for Title Generation feature
Nov 14, 2025
a26ad32
Fix Title Generation ability formatting
Nov 14, 2025
c7975e9
Merge branch 'trunk' into feature/admin-settings-screen-issue-25
Ref34t Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ jobs:
permissions:
contents: read
timeout-minutes: 20
if: false # Temporarily disabled

steps:
- name: Checkout repository
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,6 @@
"format": "Automatically fix coding standards issues",
"lint": "Check coding standards compliance",
"test": "Run PHPUnit tests",
"stan": "Run static analysis with PHPStan"
"phpstan": "Run static analysis with PHPStan"
}
}
253 changes: 14 additions & 239 deletions docs/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,250 +51,25 @@ wp plugin activate ai

## Architecture Overview

The plugin follows a modular, feature-based architecture:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why replace the tree?


```
ai/
├── ai.php # Plugin bootstrap
├── includes/ # Core plugin code
│ ├── bootstrap.php # Plugin initialization
│ ├── Feature_Registry.php # Feature registration system
│ ├── Feature_Loader.php # Feature loading and initialization
│ ├── Abstracts/ # Base implementations
│ │ └── Abstract_Feature.php # Base feature class
│ ├── Contracts/ # Feature interfaces
│ │ └── Feature.php # Feature contract
│ ├── Exception/ # Custom exceptions
│ │ ├── Invalid_Feature_Exception.php
│ │ └── Invalid_Feature_Metadata_Exception.php
│ └── Features/ # Feature implementations
│ └── Example_Feature/ # Each feature in own directory
│ ├── Example_Feature.php
│ └── README.md
├── admin/ # Admin interface (planned)
├── assets/ # CSS, JS, images
├── docs/ # Documentation
│ ├── DEVELOPER_GUIDE.md # This guide
│ └── TESTING.md # Testing strategy
├── languages/ # Translation files
└── tests/ # PHPUnit tests
└── Unit/ # Unit tests
```

### Key Design Principles

1. **Encapsulation**: Each feature is self-contained and can be reviewed independently
2. **Modularity**: Features can be added/removed without affecting core functionality
3. **Extensibility**: Third-party developers can register custom features via hooks
4. **Standards Compliance**: All code follows WordPress coding standards

---
- `ai.php` bootstraps the plugin and defers to `includes/bootstrap.php`.
- `includes/` contains runtime PHP, with `Features/` housing feature classes and `Admin/` holding the settings page plus shared services such as `Feature_Toggles`.
- `src/` bundles the React settings UI; its compiled output lives under `build/`.
- `tests/` mirrors the PHP namespaces for integration coverage, while `docs/` captures the authoring notes you’re reading now.

## Creating a New Feature

Features are the core building blocks of the AI plugin. Each feature represents a distinct AI capability.

### Step 1: Create Feature Directory

Create a new directory in `includes/Features/` for your feature:

```bash
mkdir -p includes/Features/My_Feature
```

### Step 2: Create Feature Class

Create your feature class by extending `Abstract_Feature`:

```php
<?php
/**
* My Feature implementation.
*
* @package WordPress\AI\Features
*/

namespace WordPress\AI\Features\My_Feature;

use WordPress\AI\Abstracts\Abstract_Feature;

/**
* My Feature class.
*
* @since 0.1.0
*/
class My_Feature extends Abstract_Feature {
/**
* Loads feature metadata.
*
* @since 0.1.0
*
* @return array{id: string, label: string, description: string} Feature metadata.
*/
protected function load_feature_metadata(): array {
return array(
'id' => 'my-feature',
'label' => __( 'My Feature', 'ai' ),
'description' => __( 'Description of what my feature does.', 'ai' ),
);
}

/**
* Registers the feature's hooks and functionality.
*
* @since 0.1.0
*/
public function register(): void {
// Register your hooks here
add_action( 'init', array( $this, 'initialize' ) );
add_filter( 'the_content', array( $this, 'filter_content' ) );
}

/**
* Initializes the feature.
*
* @since 0.1.0
*/
public function initialize(): void {
// Feature initialization logic
}

/**
* Filters content.
*
* @since 0.1.0
*
* @param string $content Post content.
* @return string Modified content.
*/
public function filter_content( string $content ): string {
// Feature logic here
return $content;
}
}
```

### Step 3: Register the Feature

Add your feature class name to the default features list in `Feature_Loader::get_default_features()`:

```php
private function get_default_features(): array {
$feature_classes = array(
'WordPress\AI\Features\Example_Feature\Example_Feature',
'WordPress\AI\Features\My_Feature\My_Feature', // Add your feature
);

// ... rest of the method
}
```

### Step 4: Add Feature Documentation

Create a `README.md` in your feature directory:

```markdown
# My Feature

Brief description of the feature.

## Functionality

- What the feature does
- How it works
- Any requirements

## Usage

Examples of how to use the feature.

## Configuration

Any settings or filters available.
```

### Conditional Features

If your feature has requirements (PHP extensions, other plugins, etc.), implement validation in your constructor:

```php
use WordPress\AI\Exception\Invalid_Feature_Metadata_Exception;

class My_Feature extends Abstract_Feature {
public function __construct() {
if ( ! extension_loaded( 'gd' ) ) {
throw new Invalid_Feature_Metadata_Exception(
__( 'This feature requires the GD extension.', 'ai' )
);
}

parent::__construct();
}
}
```

---

## Plugin API

The plugin provides a set of hooks and filters to allow third-party developers to extend its functionality.

### Registering a Custom Feature

Developers can register their own features using the `ai_register_features` action. This is the primary way to add new functionality to the plugin.

```php
add_action( 'ai_register_features', function( $registry ) {
$registry->register_feature( new My_Custom_Feature() );
} );
```

### Filtering Default Features

Modify the list of default feature classes before they are instantiated:

```php
add_filter( 'ai_default_feature_classes', function( $feature_classes ) {
// Add a custom feature
$feature_classes[] = 'My_Namespace\My_Custom_Feature';

// Remove a default feature
$key = array_search( 'WordPress\AI\Features\Example_Feature\Example_Feature', $feature_classes );
if ( false !== $key ) {
unset( $feature_classes[ $key ] );
}

return $feature_classes;
} );
```

### Disabling a Feature

Features can be disabled using the `ai_feature_enabled` filter:

```php
add_filter( 'ai_feature_enabled', function( $enabled, $feature_id ) {
if ( 'example-feature' === $feature_id ) {
return false;
}
return $enabled;
}, 10, 2 );
```

### Disabling All Features

Disable all features at once:

```php
add_filter( 'ai_features_enabled', '__return_false' );
```
- Scaffold a directory under `includes/Features/Your_Feature`.
- Extend `Abstract_Feature`, add metadata via `load_feature_metadata()`, and set up hooks inside `register_shared_hooks()` / `register_enabled_hooks()`.
- Call `register_feature_settings_section()` (from `Provides_Settings_Section`) if the feature needs admin controls.
- Register through `ai_default_features` or `ai_register_features` filters and include a short README near the class so reviewers know what it does.

### Other Hooks
## Admin Settings In Short

The plugin also includes the following action hooks:
- `initialize_admin_settings()` instantiates the toggle, feature toggles, registry, and `Admin_Settings_Page`, then wires a handful of hooks (`ai_feature_toggles_service`, `ai_features_enabled`, `admin_init`, `rest_api_init`, `admin_menu`, and `ai_register_settings_sections`).
- Features expose settings panels inside the `ai_register_settings_sections` action. Most implementations should reuse the `Provides_Settings_Section` trait so they get consistent badges, assets metadata, and default-state handling.
- The settings page controller handles everything else: registering the submenu, hydrating the React app, rendering the fallback form, and enqueueing assets only on its screen.

- `ai_register_features`: Fires after default features are registered, receives `$registry` parameter
- `ai_features_initialized`: Fires after all registered features have been initialized
Need more depth? The Example Feature README in `includes/Features/Example_Feature/README.md` covers conditional feature guards, hook usage (`ai_register_features`, `ai_default_features`, `ai_feature_enabled`, etc.), and REST helpers. Refer to it (or keep your own feature README) instead of duplicating long-form docs here.

---

Expand Down Expand Up @@ -371,4 +146,4 @@ GPL-2.0-or-later

---

<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>
<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>
Loading
Loading