class-restai.php
1 <?php 2 /** 3 * Plugin bootstrap. 4 * 5 * @package RESTai 6 */ 7 8 namespace RESTai; 9 10 if ( ! defined( 'ABSPATH' ) ) { 11 exit; 12 } 13 14 require_once __DIR__ . '/class-restai-icon.php'; 15 require_once __DIR__ . '/class-restai-client.php'; 16 require_once __DIR__ . '/class-restai-settings.php'; 17 require_once __DIR__ . '/class-restai-provisioner.php'; 18 require_once __DIR__ . '/class-restai-rest.php'; 19 require_once __DIR__ . '/class-restai-content.php'; 20 require_once __DIR__ . '/class-restai-seo.php'; 21 require_once __DIR__ . '/class-restai-images.php'; 22 require_once __DIR__ . '/class-restai-translation.php'; 23 require_once __DIR__ . '/class-restai-comments.php'; 24 require_once __DIR__ . '/class-restai-woocommerce.php'; 25 require_once __DIR__ . '/class-restai-knowledge-sync.php'; 26 require_once __DIR__ . '/class-restai-search.php'; 27 require_once __DIR__ . '/class-restai-email.php'; 28 require_once __DIR__ . '/class-restai-analytics.php'; 29 require_once __DIR__ . '/class-restai-cron.php'; 30 require_once __DIR__ . '/class-restai-widget.php'; 31 32 /** 33 * Singleton entry point. 34 */ 35 final class Plugin { 36 37 /** @var Plugin|null */ 38 private static $instance = null; 39 40 /** @var Client */ 41 public $client; 42 43 /** @var Settings */ 44 public $settings; 45 46 /** @var Provisioner */ 47 public $provisioner; 48 49 /** 50 * Get / create the singleton. 51 */ 52 public static function instance() { 53 if ( null === self::$instance ) { 54 self::$instance = new self(); 55 self::$instance->boot(); 56 } 57 return self::$instance; 58 } 59 60 /** 61 * Wire everything up. 62 */ 63 private function boot() { 64 load_plugin_textdomain( 'restai', false, dirname( RESTAI_PLUGIN_BASENAME ) . '/languages' ); 65 66 $this->client = new Client(); 67 $this->settings = new Settings( $this->client ); 68 $this->provisioner = new Provisioner( $this->client ); 69 70 new Rest_API( $this->client ); 71 new Content( $this->client ); 72 new SEO( $this->client ); 73 new Images( $this->client ); 74 new Translation( $this->client ); 75 new Comments( $this->client ); 76 new WooCommerce_Integration( $this->client ); 77 new Knowledge_Sync( $this->client ); 78 new Search( $this->client ); 79 new Email_Personalization( $this->client ); 80 new Analytics( $this->client ); 81 new Cron( $this->client ); 82 new Widget(); 83 84 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); 85 add_filter( 'plugin_action_links_' . RESTAI_PLUGIN_BASENAME, array( $this, 'plugin_action_links' ) ); 86 } 87 88 /** 89 * Enqueue admin CSS/JS only on plugin screens or post-edit screens. 90 * 91 * @param string $hook Current admin page. 92 */ 93 public function enqueue_admin_assets( $hook ) { 94 $is_plugin_screen = ( false !== strpos( $hook, 'restai' ) ); 95 $is_editor_screen = in_array( $hook, array( 'post.php', 'post-new.php' ), true ); 96 97 if ( ! $is_plugin_screen && ! $is_editor_screen ) { 98 return; 99 } 100 101 wp_enqueue_style( 102 'restai-admin', 103 RESTAI_PLUGIN_URL . 'admin/css/admin.css', 104 array(), 105 RESTAI_VERSION 106 ); 107 108 wp_enqueue_script( 109 'restai-admin', 110 RESTAI_PLUGIN_URL . 'admin/js/admin.js', 111 array( 'jquery', 'wp-api-fetch' ), 112 RESTAI_VERSION, 113 true 114 ); 115 116 wp_localize_script( 117 'restai-admin', 118 'RESTaiAdmin', 119 array( 120 'restUrl' => esc_url_raw( rest_url( 'restai/v1' ) ), 121 'nonce' => wp_create_nonce( 'wp_rest' ), 122 'i18n' => array( 123 'generating' => esc_html__( 'Generating…', 'restai' ), 124 'generate' => esc_html__( 'Generate with AI', 'restai' ), 125 'error' => esc_html__( 'Something went wrong. Please try again.', 'restai' ), 126 'no_project' => esc_html__( 'No project mapped for this task. Configure it in Settings → RESTai.', 'restai' ), 127 'confirm_replace' => esc_html__( 'Replace the current content with the AI-generated version?', 'restai' ), 128 ), 129 'connected' => self::is_connected(), 130 ) 131 ); 132 133 if ( $is_editor_screen ) { 134 wp_enqueue_script( 135 'restai-editor', 136 RESTAI_PLUGIN_URL . 'admin/js/editor.js', 137 array( 'restai-admin', 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-data', 'wp-i18n' ), 138 RESTAI_VERSION, 139 true 140 ); 141 } 142 } 143 144 /** 145 * Add a "Settings" link in the plugins list. 146 */ 147 public function plugin_action_links( $links ) { 148 $settings_link = sprintf( 149 '<a href="%s">%s</a>', 150 esc_url( admin_url( 'options-general.php?page=restai' ) ), 151 esc_html__( 'Settings', 'restai' ) 152 ); 153 array_unshift( $links, $settings_link ); 154 return $links; 155 } 156 157 /** 158 * @return bool True if the plugin has a usable connection to RESTai. 159 */ 160 public static function is_connected() { 161 $settings = get_option( 'restai_settings', array() ); 162 return ! empty( $settings['url'] ) && ! empty( $settings['api_key'] ); 163 } 164 165 /** 166 * Activation hook. 167 */ 168 public static function activate() { 169 if ( false === get_option( 'restai_settings' ) ) { 170 add_option( 171 'restai_settings', 172 array( 173 'url' => '', 174 'api_key' => '', 175 'enable_widget' => false, 176 'enable_search' => false, 177 'enable_knowledge' => false, 178 'enable_moderation' => false, 179 'enable_email_ai' => false, 180 'auto_alt_text' => true, 181 ) 182 ); 183 } 184 if ( false === get_option( 'restai_project_map' ) ) { 185 add_option( 'restai_project_map', array() ); 186 } 187 } 188 189 /** 190 * Deactivation hook — clear scheduled jobs. 191 */ 192 public static function deactivate() { 193 wp_clear_scheduled_hook( 'restai_knowledge_sync' ); 194 wp_clear_scheduled_hook( 'restai_seo_audit' ); 195 } 196 }