refactor: Cleanup git state - commit all staged changes

Major refactoring cleanup:
- Add new controller architecture (class-controller-*.php)
- Add new settings-v2 UI (views/settings-v2/)
- Add new CSS architecture (agentic-sidebar.css, tokens)
- Add esbuild build pipeline (scripts/build.js, package.json)
- Add composer dependencies (vendor/)
- Add frontend src directory (assets/js/src/index.jsx)
- Add documentation files
- Remove old/obsolete files (class-settings.php, old CSS)

This commits all pending changes from previous refactoring efforts.
This commit is contained in:
Dwindi Ramadhana
2026-06-17 05:27:58 +07:00
parent d3f142222c
commit 690991c526
7963 changed files with 941566 additions and 67372 deletions

View File

@@ -7,8 +7,8 @@
* @package WP_Agentic_Writer
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
if (!defined("ABSPATH")) {
exit();
}
/**
@@ -17,211 +17,346 @@ if ( ! defined( 'ABSPATH' ) ) {
*
* @since 0.2.0
*/
class WPAW_Provider_Selection_Result {
public $provider; // Provider instance
public $selected_provider; // Original requested provider name
public $actual_provider; // Actually used provider name (may differ if fallback)
public $fallback_used; // True if fallback occurred
public $warnings; // Array of warning messages
class WPAW_Provider_Selection_Result
{
public $provider; // Provider instance
public $selected_provider; // Original requested provider name
public $actual_provider; // Actually used provider name (may differ if fallback)
public $fallback_used; // True if fallback occurred
public $warnings; // Array of warning messages
public function __construct( $provider, $selected, $actual, $fallback, $warnings = array() ) {
$this->provider = $provider;
$this->selected_provider = $selected;
$this->actual_provider = $actual;
$this->fallback_used = $fallback;
$this->warnings = $warnings;
}
public function __construct(
$provider,
$selected,
$actual,
$fallback,
$warnings = [],
) {
$this->provider = $provider;
$this->selected_provider = $selected;
$this->actual_provider = $actual;
$this->fallback_used = $fallback;
$this->warnings = $warnings;
}
}
class WP_Agentic_Writer_Provider_Manager {
/**
* Get provider instance for specific task type
*
* @param string $type Task type (chat, clarity, planning, writing, refinement, image).
* @return WPAW_Provider_Selection_Result Provider selection result with metadata.
*/
public static function get_provider_for_task( $type ) {
$settings = get_option( 'wp_agentic_writer_settings', array() );
$task_providers = $settings['task_providers'] ?? array();
$allow_openrouter_fallback = ! empty( $settings['allow_openrouter_fallback'] );
class WP_Agentic_Writer_Provider_Manager
{
/**
* Transient cache TTL for connection test results (5 minutes).
*
* @var int
*/
const CONNECTION_TEST_CACHE_TTL = 300;
// Determine which provider to use for this task
$requested_provider = $task_providers[ $type ] ?? 'openrouter';
/**
* Transient cache key prefix for connection tests.
*
* @var string
*/
const CONNECTION_TEST_CACHE_PREFIX = "wpaw_conn_test_";
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( "WPAW Provider Manager: task={$type}, provider_name={$requested_provider}, task_providers=" . json_encode( $task_providers ) );
}
/**
* Get provider instance for specific task type
*
* @param string $type Task type (chat, clarity, planning, writing, refinement, image).
* @return WPAW_Provider_Selection_Result Provider selection result with metadata.
*/
public static function get_provider_for_task($type)
{
$settings = get_option("wp_agentic_writer_settings", []);
$task_providers = $settings["task_providers"] ?? [];
$allow_openrouter_fallback = !empty(
$settings["allow_openrouter_fallback"]
);
$warnings = array();
$fallback_used = false;
$actual_provider = $requested_provider;
// Determine which provider to use for this task
$requested_provider = $task_providers[$type] ?? "openrouter";
// Get provider instance with fallback logic
$provider = self::get_provider_instance( $requested_provider, $type );
if (defined("WP_DEBUG") && WP_DEBUG) {
error_log(
"WPAW Provider Manager: task={$type}, provider_name={$requested_provider}, task_providers=" .
json_encode($task_providers),
);
}
$can_fallback_to_openrouter = ( 'openrouter' === $requested_provider ) || $allow_openrouter_fallback;
$warnings = [];
$fallback_used = false;
$actual_provider = $requested_provider;
// If provider not configured or unavailable.
if ( ! $provider || ! $provider->is_configured() ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( "Provider '{$requested_provider}' not available for task '{$type}'" );
}
// Get provider instance with fallback logic
$provider = self::get_provider_instance($requested_provider, $type);
// Never silently spend OpenRouter credits when user selected another provider.
if ( ! $can_fallback_to_openrouter ) {
$warnings[] = "Provider '{$requested_provider}' unavailable. No automatic fallback was applied.";
return new WPAW_Provider_Selection_Result(
$provider,
$requested_provider,
$requested_provider,
false,
$warnings
);
}
$can_fallback_to_openrouter =
"openrouter" === $requested_provider || $allow_openrouter_fallback;
$warnings[] = "Provider '{$requested_provider}' unavailable, fell back to OpenRouter";
$provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
$actual_provider = 'openrouter';
$fallback_used = true;
}
// If provider not configured or unavailable.
if (!$provider || !$provider->is_configured()) {
if (defined("WP_DEBUG") && WP_DEBUG) {
error_log(
"Provider '{$requested_provider}' not available for task '{$type}'",
);
}
// For local backend, verify it's actually reachable before using it
if ( 'local_backend' === $requested_provider && ! $fallback_used && method_exists( $provider, 'test_connection' ) ) {
$test_result = $provider->test_connection();
if ( is_wp_error( $test_result ) ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( "Local Backend not reachable for task '{$type}'. Error: " . $test_result->get_error_message() );
}
if ( $can_fallback_to_openrouter ) {
$warnings[] = "Local Backend not reachable, fell back to OpenRouter.";
$provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
$actual_provider = 'openrouter';
$fallback_used = true;
} else {
$warnings[] = "Local Backend not reachable. No automatic fallback was applied.";
}
}
}
// Never silently spend OpenRouter credits when user selected another provider.
if (!$can_fallback_to_openrouter) {
$warnings[] = "Provider '{$requested_provider}' unavailable. No automatic fallback was applied.";
return new WPAW_Provider_Selection_Result(
$provider,
$requested_provider,
$requested_provider,
false,
$warnings,
);
}
return new WPAW_Provider_Selection_Result(
$provider,
$requested_provider,
$actual_provider,
$fallback_used,
$warnings
);
}
$warnings[] = "Provider '{$requested_provider}' unavailable, fell back to OpenRouter";
$provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
$actual_provider = "openrouter";
$fallback_used = true;
}
/**
* Get provider instance by name
*
* @param string $provider_name Provider identifier.
* @param string $task_type Task type for validation.
* @return WP_Agentic_Writer_AI_Provider_Interface|null Provider instance or null.
*/
private static function get_provider_instance( $provider_name, $task_type ) {
switch ( $provider_name ) {
case 'local_backend':
if ( ! class_exists( 'WP_Agentic_Writer_Local_Backend_Provider' ) ) {
require_once plugin_dir_path( __FILE__ ) . 'class-local-backend-provider.php';
}
$provider = new WP_Agentic_Writer_Local_Backend_Provider();
break;
// For custom endpoint, verify it's actually reachable before using it.
// Use transient cache to avoid testing connection on every request (5 min TTL).
if (
"local_backend" === $requested_provider &&
!$fallback_used &&
method_exists($provider, "test_connection")
) {
$cache_key =
self::CONNECTION_TEST_CACHE_PREFIX .
md5($requested_provider . $type);
$cached_result = get_transient($cache_key);
case 'codex':
if ( ! class_exists( 'WP_Agentic_Writer_Codex_Provider' ) ) {
require_once plugin_dir_path( __FILE__ ) . 'class-codex-provider.php';
}
$provider = new WP_Agentic_Writer_Codex_Provider();
break;
if (false !== $cached_result) {
// Use cached result
if (is_wp_error($cached_result)) {
$test_result = $cached_result;
} else {
// Cached success - skip test entirely
if (defined("WP_DEBUG") && WP_DEBUG) {
error_log(
"WPAW: Using cached connection test result for '{$requested_provider}'",
);
}
$test_result = null; // null means "test passed"
}
} else {
// No cache - run the actual test
$test_result = $provider->test_connection();
case 'openrouter':
default:
$provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
break;
}
// Cache the result for CONNECTION_TEST_CACHE_TTL seconds
set_transient(
$cache_key,
$test_result,
self::CONNECTION_TEST_CACHE_TTL,
);
}
// Validate provider supports this task type
if ( $provider && ! $provider->supports_task_type( $task_type ) ) {
error_log( "Provider '{$provider_name}' does not support task type '{$task_type}'" );
return null;
}
if (isset($test_result) && is_wp_error($test_result)) {
if (defined("WP_DEBUG") && WP_DEBUG) {
error_log(
"Custom endpoint not reachable for task '{$type}'. Error: " .
$test_result->get_error_message(),
);
}
if ($can_fallback_to_openrouter) {
$warnings[] =
"Custom endpoint not reachable, fell back to OpenRouter.";
$provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
$actual_provider = "openrouter";
$fallback_used = true;
} else {
$warnings[] =
"Custom endpoint not reachable. No automatic fallback was applied.";
}
}
}
return $provider;
}
return new WPAW_Provider_Selection_Result(
$provider,
$requested_provider,
$actual_provider,
$fallback_used,
$warnings,
);
}
/**
* Get all available providers with their status
*
* @return array Array of provider info with name, status, supported tasks.
*/
public static function get_available_providers() {
$providers = array();
/**
* Get provider instance by name
*
* @param string $provider_name Provider identifier.
* @param string $task_type Task type for validation.
* @return WP_Agentic_Writer_AI_Provider_Interface|null Provider instance or null.
*/
private static function get_provider_instance($provider_name, $task_type)
{
switch ($provider_name) {
case "local_backend":
if (!class_exists("WP_Agentic_Writer_Local_Backend_Provider")) {
require_once plugin_dir_path(__FILE__) .
"class-local-backend-provider.php";
}
$provider = new WP_Agentic_Writer_Local_Backend_Provider();
break;
// OpenRouter (always available)
$openrouter = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
$providers['openrouter'] = array(
'name' => 'OpenRouter',
'configured' => $openrouter->is_configured(),
'supports' => array( 'chat', 'clarity', 'planning', 'writing', 'refinement', 'image' ),
'icon' => '☁️',
);
case "codex":
if (!class_exists("WP_Agentic_Writer_Codex_Provider")) {
require_once plugin_dir_path(__FILE__) .
"class-codex-provider.php";
}
$provider = new WP_Agentic_Writer_Codex_Provider();
break;
// Local Backend
if ( class_exists( 'WP_Agentic_Writer_Local_Backend_Provider' ) ) {
$local = new WP_Agentic_Writer_Local_Backend_Provider();
$providers['local_backend'] = array(
'name' => 'Local Backend',
'configured' => $local->is_configured(),
'supports' => array( 'chat', 'clarity', 'planning', 'writing', 'refinement' ),
'icon' => '🏠',
);
}
case "openrouter":
default:
$provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
break;
}
// Codex
if ( class_exists( 'WP_Agentic_Writer_Codex_Provider' ) ) {
$codex = new WP_Agentic_Writer_Codex_Provider();
$providers['codex'] = array(
'name' => 'Codex (OpenAI)',
'configured' => $codex->is_configured(),
'supports' => array( 'chat', 'clarity', 'planning', 'writing', 'refinement' ),
'icon' => '🔗',
);
}
// Validate provider supports this task type
if ($provider && !$provider->supports_task_type($task_type)) {
error_log(
"Provider '{$provider_name}' does not support task type '{$task_type}'",
);
return null;
}
return $providers;
}
return $provider;
}
/**
* Test all configured providers
*
* @return array Results of connection tests.
*/
public static function test_all_providers() {
$results = array();
$providers = self::get_available_providers();
/**
* Get all available providers with their status
*
* @return array Array of provider info with name, status, supported tasks.
*/
public static function get_available_providers()
{
$providers = [];
foreach ( $providers as $key => $info ) {
if ( ! $info['configured'] ) {
$results[ $key ] = array(
'success' => false,
'message' => 'Not configured',
);
continue;
}
// OpenRouter (always available)
$openrouter = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
$providers["openrouter"] = [
"name" => "OpenRouter",
"configured" => $openrouter->is_configured(),
"supports" => [
"chat",
"clarity",
"planning",
"writing",
"refinement",
"image",
],
"icon" => "☁️",
];
$provider = self::get_provider_instance( $key, 'chat' );
if ( $provider ) {
$test_result = $provider->test_connection();
$results[ $key ] = is_wp_error( $test_result )
? array(
'success' => false,
'message' => $test_result->get_error_message(),
)
: $test_result;
}
}
// Custom Endpoint
if (class_exists("WP_Agentic_Writer_Local_Backend_Provider")) {
$local = new WP_Agentic_Writer_Local_Backend_Provider();
$providers["local_backend"] = [
"name" => "Custom Endpoint",
"configured" => $local->is_configured(),
"supports" => [
"chat",
"clarity",
"planning",
"writing",
"refinement",
],
"icon" => "🏠",
];
}
return $results;
}
// Codex
if (class_exists("WP_Agentic_Writer_Codex_Provider")) {
$codex = new WP_Agentic_Writer_Codex_Provider();
$providers["codex"] = [
"name" => "Codex (OpenAI)",
"configured" => $codex->is_configured(),
"supports" => [
"chat",
"clarity",
"planning",
"writing",
"refinement",
],
"icon" => "🔗",
];
}
return $providers;
}
/**
* Test all configured providers
*
* @return array Results of connection tests.
*/
public static function test_all_providers()
{
$results = [];
$providers = self::get_available_providers();
foreach ($providers as $key => $info) {
if (!$info["configured"]) {
$results[$key] = [
"success" => false,
"message" => "Not configured",
];
continue;
}
$provider = self::get_provider_instance($key, "chat");
if ($provider) {
$test_result = $provider->test_connection();
$results[$key] = is_wp_error($test_result)
? [
"success" => false,
"message" => $test_result->get_error_message(),
]
: $test_result;
}
}
return $results;
}
/**
* Clear the connection test transient cache.
* Call this when local backend settings are updated.
*
* @return int Number of cache entries deleted.
*/
public static function clear_connection_test_cache()
{
global $wpdb;
$prefix = self::CONNECTION_TEST_CACHE_PREFIX;
$count = 0;
// Delete all transients with our prefix
$transients = $wpdb->get_col(
$wpdb->prepare(
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
$wpdb->esc_like("_transient_") . $prefix . "%",
),
);
foreach ($transients as $transient) {
// Strip '_transient_' prefix if present
$key = $transient;
if (0 === strpos($key, "_transient_")) {
$key = substr($key, 11);
}
if (delete_transient($key)) {
$count++;
}
}
if (defined("WP_DEBUG") && WP_DEBUG) {
error_log("WPAW: Cleared {$count} connection test cache entries");
}
return $count;
}
}