Files
wp-agentic-writer/wp-agentic-writer.php
Dwindi Ramadhana 690991c526 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.
2026-06-17 05:27:58 +07:00

349 lines
10 KiB
PHP

<?php
/**
* Plugin Name: WP Agentic Writer
* Plugin URI: https://github.com/wp-agentic-writer
* Description: Plan-first AI writing workflow for WordPress. Scribble → Research → Plan → Execute → Revise
* Version: 0.1.3
* Author: WP Agentic Writer
* Author URI: https://github.com/wp-agentic-writer
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: wp-agentic-writer
* Domain Path: /languages
* Requires at least: 6.6
* Requires PHP: 7.4
*
* @package WP_Agentic_Writer
*/
// Exit if accessed directly.
if (!defined("ABSPATH")) {
exit();
}
// Plugin version.
define("WP_AGENTIC_WRITER_VERSION", "0.1.3");
// Plugin file path.
define("WP_AGENTIC_WRITER_FILE", __FILE__);
// Plugin directory path.
define("WP_AGENTIC_WRITER_DIR", plugin_dir_path(__FILE__));
// Alias for backward compatibility.
define("WPAW_PLUGIN_DIR", WP_AGENTIC_WRITER_DIR);
// Plugin directory URL (plugin_dir_url already includes trailing slash).
define(
"WP_AGENTIC_WRITER_URL",
untrailingslashit(plugin_dir_url(__FILE__)) . "/",
);
// Include autoloader.
require_once WP_AGENTIC_WRITER_DIR . "includes/class-autoloader.php";
// Include provider interface and manager.
require_once WP_AGENTIC_WRITER_DIR . "includes/interface-ai-provider.php";
require_once WP_AGENTIC_WRITER_DIR . "includes/class-provider-manager.php";
// Include WordPress 7.0 AI Client wrapper (backward compatible).
require_once WP_AGENTIC_WRITER_DIR . "includes/class-wp-ai-client-wrapper.php";
// Include conversation manager for session-based chat history.
require_once WP_AGENTIC_WRITER_DIR .
"includes/class-conversation-migration.php";
require_once WP_AGENTIC_WRITER_DIR . "includes/class-conversation-manager.php";
// Include model registry for centralized model defaults.
require_once WP_AGENTIC_WRITER_DIR . "includes/class-model-registry.php";
// Include shared REST rate limiter used by endpoint controllers.
require_once WP_AGENTIC_WRITER_DIR . "includes/class-rate-limiter.php";
// Initialize the plugin.
function wp_agentic_writer_init()
{
// Load plugin text domain.
load_plugin_textdomain(
"wp-agentic-writer",
false,
dirname(plugin_basename(__FILE__)) . "/languages/",
);
// Always initialize Gutenberg sidebar for REST API routes.
WP_Agentic_Writer_Gutenberg_Sidebar::get_instance();
// Always initialize cost tracker hooks (REST API calls need this).
WP_Agentic_Writer_Cost_Tracker::get_instance();
// Schedule image cleanup cron job if not already scheduled.
if (!wp_next_scheduled("wpaw_cleanup_temp_images")) {
wp_schedule_event(time(), "daily", "wpaw_cleanup_temp_images");
}
// Initialize SEO Schema Agent
WP_Agentic_Writer_SEO_Schema::get_instance();
// Check if we're on the admin side.
if (is_admin()) {
// Initialize settings V2.
require_once WP_AGENTIC_WRITER_DIR . "includes/class-settings-v2.php";
WP_Agentic_Writer_Settings_V2::get_instance();
// Initialize admin columns.
WP_Agentic_Writer_Admin_Columns::get_instance();
}
}
add_action("plugins_loaded", "wp_agentic_writer_init");
// Hook for image cleanup cron job.
add_action("wpaw_cleanup_temp_images", "wp_agentic_writer_cleanup_temp_images");
/**
* Cleanup old temp images (7+ days).
*
* @since 0.1.0
*/
function wp_agentic_writer_cleanup_temp_images()
{
WP_Agentic_Writer_Image_Manager::get_instance()->cleanup_old_temp_images();
}
// Activation hook.
register_activation_hook(__FILE__, "wp_agentic_writer_activate");
/**
* Plugin activation.
*
* @since 0.1.0
*/
function wp_agentic_writer_activate()
{
// Set default options using model registry for consistency.
$registry_defaults = WPAW_Model_Registry::get_activation_defaults();
$default_options = [
"openrouter_api_key" => "",
"planning_model" => $registry_defaults["planning_model"],
"execution_model" => $registry_defaults["execution_model"],
"image_model" => $registry_defaults["image_model"],
"web_search_enabled" => false,
"search_engine" => "auto",
"search_depth" => "medium",
"cost_tracking_enabled" => true,
"enable_clarification_quiz" => true,
"clarity_confidence_threshold" => "0.6",
"chat_history_limit" => 20,
"preferred_languages" => ["auto", "English", "Indonesian"],
"custom_languages" => [],
];
add_option("wp_agentic_writer_settings", $default_options);
// Set default custom models from registry (separate option for custom models)
$registry = WPAW_Model_Registry::get_registry();
$default_custom_models = [];
foreach ($registry["image_models"] as $id => $name) {
$default_custom_models[] = [
"id" => $id,
"name" => $name,
"type" => "image",
];
}
add_option("wp_agentic_writer_custom_models", $default_custom_models);
// Create cost tracking table.
wp_agentic_writer_create_cost_table();
// Create image management tables.
WP_Agentic_Writer_Image_Manager::get_instance()->create_tables();
// Create conversations table.
require_once WP_AGENTIC_WRITER_DIR .
"includes/class-conversation-migration.php";
wpaw_create_conversations_table();
}
/**
* Create cost tracking table.
*
* @since 0.1.0
*/
function wp_agentic_writer_create_cost_table()
{
global $wpdb;
$table_name = $wpdb->prefix . "wpaw_cost_tracking";
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
post_id bigint(20) NOT NULL,
session_id varchar(32) DEFAULT '' NOT NULL,
model varchar(255) NOT NULL,
provider varchar(50) DEFAULT 'openrouter' NOT NULL,
action varchar(50) NOT NULL,
input_tokens int(11) NOT NULL,
output_tokens int(11) NOT NULL,
cost decimal(10,6) NOT NULL,
status varchar(20) DEFAULT 'success' NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id),
KEY post_id (post_id),
KEY session_id (session_id),
KEY provider (provider),
KEY action (action),
KEY created_at (created_at)
) $charset_collate;";
require_once ABSPATH . "wp-admin/includes/upgrade.php";
dbDelta($sql);
}
// Version-based table creation (runs on plugins_loaded to ensure tables exist).
add_action("plugins_loaded", "wp_agentic_writer_maybe_create_tables");
/**
* Create database tables if they don't exist or version is outdated.
*
* @since 0.1.0
*/
function wp_agentic_writer_maybe_create_tables()
{
// Cost tracking table - controlled by main db version.
$current_version = get_option("wpaw_db_version", "0");
$required_version = "1.1.0";
if (version_compare($current_version, $required_version, "<")) {
// Create cost tracking table.
wp_agentic_writer_create_cost_table();
// Create image management tables.
WP_Agentic_Writer_Image_Manager::get_instance()->create_tables();
// Create conversations table (migrate if needed).
if (!function_exists("wpaw_create_conversations_table")) {
require_once WP_AGENTIC_WRITER_DIR .
"includes/class-conversation-migration.php";
}
wpaw_create_conversations_table();
// Update version.
update_option("wpaw_db_version", $required_version);
} else {
// Even if main version is current, still check conversation table independently.
if (!function_exists("wpaw_create_conversations_table")) {
require_once WP_AGENTIC_WRITER_DIR .
"includes/class-conversation-migration.php";
}
$conv_version = get_option("wpaw_conversations_db_version", "0");
if (version_compare($conv_version, "0.1.4", "<")) {
wpaw_create_conversations_table();
}
}
}
// Deactivation hook.
register_deactivation_hook(__FILE__, "wp_agentic_writer_deactivate");
/**
* Plugin deactivation.
*
* @since 0.1.0
*/
function wp_agentic_writer_deactivate()
{
// Clear scheduled cron jobs.
$timestamp = wp_next_scheduled("wpaw_cleanup_temp_images");
if ($timestamp) {
wp_unschedule_event($timestamp, "wpaw_cleanup_temp_images");
}
wp_clear_scheduled_hook("wpaw_cleanup_old_sessions");
}
// Uninstall hook.
register_uninstall_hook(__FILE__, "wp_agentic_writer_uninstall");
/**
* Plugin uninstall.
*
* Removes all plugin data including settings, database tables,
* post meta, user meta, transients, scheduled events, and temp files.
*
* @since 0.1.0
*/
function wp_agentic_writer_uninstall()
{
global $wpdb;
// Delete options.
delete_option("wp_agentic_writer_settings");
delete_option("wpaw_db_version");
delete_option("wpaw_conversations_db_version");
delete_option("wp_agentic_writer_custom_models");
// Delete post meta.
$post_meta_keys = [
"_wpaw_plan",
"_wpaw_chat_history",
"_wpaw_memory",
"_wpaw_post_config",
"_wpaw_focus_keyword",
"_wpaw_writing_status",
"_wpaw_current_section",
"_wpaw_sections_written",
"_wpaw_writing_state_updated",
"_wpaw_plan_id",
"_wpaw_resume_token",
];
foreach ($post_meta_keys as $key) {
delete_post_meta_by_key($key);
}
// Delete user meta.
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s",
"wpaw_%",
),
);
// Delete database tables.
$tables = [
$wpdb->prefix . "wpaw_cost_tracking",
$wpdb->prefix . "wpaw_images",
$wpdb->prefix . "wpaw_images_variants",
$wpdb->prefix . "wpaw_conversations",
];
foreach ($tables as $table) {
$wpdb->query("DROP TABLE IF EXISTS {$table}");
}
// Clear transients.
delete_transient("wpaw_openrouter_models");
delete_transient("wpaw_openrouter_model_objects");
delete_transient("wpaw_openrouter_model_ids");
// Unschedule cron events.
wp_clear_scheduled_hook("wpaw_cleanup_old_sessions");
wp_clear_scheduled_hook("wpaw_daily_cleanup");
// Delete temp image directory.
$upload_dir = wp_upload_dir();
$temp_dir = $upload_dir["basedir"] . "/wpaw";
if (file_exists($temp_dir)) {
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$temp_dir,
RecursiveDirectoryIterator::SKIP_DOTS,
),
RecursiveIteratorIterator::CHILD_FIRST,
);
foreach ($files as $fileinfo) {
$todo = $fileinfo->isDir() ? "rmdir" : "unlink";
$todo($fileinfo->getRealPath());
}
rmdir($temp_dir);
}
}