← All changes
|
includes/admin/tools/charitable-tools-admin-hooks.php
+153
-0
1.8.12
→
1.8.13
View file →
| @@ -174,4 +174,157 @@ | ||
| 174 | 174 | add_action( 'wp_ajax_charitable_export_logs_csv', array( 'Charitable_Log', 'ajax_export_csv' ) ); |
| 175 | 175 | add_action( 'wp_ajax_charitable_toggle_logging', array( 'Charitable_Log', 'ajax_toggle_logging' ) ); |
| 176 | 176 | add_action( 'wp_ajax_charitable_save_log_retention', array( 'Charitable_Log', 'ajax_save_retention' ) ); |
| 177 | 177 | add_action( 'admin_enqueue_scripts', array( 'Charitable_Log', 'enqueue_scripts' ) ); |
| 178 | + | |
| 179 | +/** | |
| 180 | + * Tools > AI MCP. | |
| 181 | + * | |
| 182 | + * Surfaces the Abilities API, which ships with no UI of its own, and carries the | |
| 183 | + * AI write-access toggle. Charitable_Tools_AI_MCP is autoloaded via the classmap. | |
| 184 | + * | |
| 185 | + * Ported from Charitable Pro (pinned commit 4f84275197) for Lite 1.8.13. The | |
| 186 | + * `ai-mcp` tab itself is registered directly in | |
| 187 | + * Charitable_Tools::get_sections(), and the "no form / no Save Changes button" | |
| 188 | + * behaviour Pro gets from its `charitable_tools_tabs_without_form` filter is | |
| 189 | + * given here by adding 'ai-mcp' to the `$charitable_tab_no_form_tag` array in | |
| 190 | + * includes/admin/views/tools/tools.php - the hardcoded-array convention that | |
| 191 | + * file already uses for 'import', 'export', 'system-info' and the rest, rather | |
| 192 | + * than porting a filter Lite's view template does not read. | |
| 193 | + * | |
| 194 | + * @since 1.8.13 | |
| 195 | + */ | |
| 196 | +add_filter( | |
| 197 | + 'charitable_tools_tab_fields_ai-mcp', | |
| 198 | + array( Charitable_Tools_AI_MCP::get_instance(), 'add_fields' ), | |
| 199 | + 5 | |
| 200 | +); | |
| 201 | + | |
| 202 | +/** | |
| 203 | + * Enqueue the AI MCP panel assets, on that one tab only. | |
| 204 | + * | |
| 205 | + * @since 1.8.13 | |
| 206 | + * | |
| 207 | + * @return void | |
| 208 | + */ | |
| 209 | +add_action( | |
| 210 | + 'admin_enqueue_scripts', | |
| 211 | + function () { | |
| 212 | + | |
| 213 | + if ( ! function_exists( 'charitable_is_tools_view' ) || ! charitable_is_tools_view() ) { | |
| 214 | + return; | |
| 215 | + } | |
| 216 | + | |
| 217 | + $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 218 | + | |
| 219 | + if ( 'ai-mcp' !== $tab ) { | |
| 220 | + return; | |
| 221 | + } | |
| 222 | + | |
| 223 | + wp_enqueue_style( 'dashicons' ); | |
| 224 | + | |
| 225 | + wp_enqueue_style( | |
| 226 | + 'charitable-ai-mcp', | |
| 227 | + charitable()->get_path( 'assets', false ) . 'css/admin/charitable-ai-mcp.css', | |
| 228 | + array(), | |
| 229 | + charitable()->get_version() | |
| 230 | + ); | |
| 231 | + | |
| 232 | + if ( ! current_user_can( 'manage_charitable_settings' ) ) { | |
| 233 | + return; | |
| 234 | + } | |
| 235 | + | |
| 236 | + /* | |
| 237 | + * jquery-confirm powers the "Watch video" modal. Guarded the same way | |
| 238 | + * Charitable_Admin_Splash guards it, because the splash is enqueued on | |
| 239 | + * this same screen and whichever runs first should win. Do NOT rely on | |
| 240 | + * the splash having done it: the link has to work on a site where the | |
| 241 | + * splash is suppressed (hide_announcements), and without the library the | |
| 242 | + * handler falls through to the anchor's YouTube href. | |
| 243 | + */ | |
| 244 | + if ( ! wp_style_is( 'jquery-confirm', 'enqueued' ) ) { | |
| 245 | + wp_enqueue_style( | |
| 246 | + 'jquery-confirm', | |
| 247 | + charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.confirm/jquery-confirm.min.css', | |
| 248 | + null, | |
| 249 | + '3.3.4' | |
| 250 | + ); | |
| 251 | + } | |
| 252 | + | |
| 253 | + if ( ! wp_script_is( 'jquery-confirm', 'enqueued' ) ) { | |
| 254 | + wp_enqueue_script( | |
| 255 | + 'jquery-confirm', | |
| 256 | + charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.confirm/jquery-confirm.min.js', | |
| 257 | + array( 'jquery' ), | |
| 258 | + '3.3.4', | |
| 259 | + false | |
| 260 | + ); | |
| 261 | + } | |
| 262 | + | |
| 263 | + wp_enqueue_script( | |
| 264 | + 'charitable-ai-mcp', | |
| 265 | + charitable()->get_path( 'assets', false ) . 'js/admin/charitable-ai-mcp.js', | |
| 266 | + array( 'jquery', 'jquery-confirm' ), | |
| 267 | + charitable()->get_version(), | |
| 268 | + true | |
| 269 | + ); | |
| 270 | + | |
| 271 | + wp_localize_script( | |
| 272 | + 'charitable-ai-mcp', | |
| 273 | + 'charitable_ai_mcp', | |
| 274 | + array( | |
| 275 | + 'ajax_url' => admin_url( 'admin-ajax.php' ), | |
| 276 | + 'nonce' => wp_create_nonce( 'charitable_ai_mcp_toggle' ), | |
| 277 | + // Charitable_Admin_Plugins_Third_Party guards both the install and | |
| 278 | + // the activate call with the shared 'charitable-admin' nonce, so the | |
| 279 | + // in-place bridge install needs that one rather than the toggle nonce. | |
| 280 | + 'plugin_nonce' => wp_create_nonce( 'charitable-admin' ), | |
| 281 | + 'i18n' => array( | |
| 282 | + 'error' => __( 'That could not be saved. Please try again.', 'charitable' ), | |
| 283 | + 'installing' => __( 'Installing WPVibe…', 'charitable' ), | |
| 284 | + 'activating' => __( 'Activating WPVibe…', 'charitable' ), | |
| 285 | + 'installError' => __( 'WPVibe could not be installed. Install it from the Plugins screen instead.', 'charitable' ), | |
| 286 | + /* The iframe's title attribute, read by screen readers in the video modal. */ | |
| 287 | + 'videoTitle' => esc_attr__( 'Using Charitable with AI', 'charitable' ), | |
| 288 | + /* | |
| 289 | + * The AI Activity toggle's accessible name, which is the only | |
| 290 | + * thing that can say which way the control goes - its visible | |
| 291 | + * label is a chevron. The collapsed wording matches the | |
| 292 | + * `screen-reader-text` rendered in views/ai-mcp-activity.php, | |
| 293 | + * since that is the state the panel loads in. | |
| 294 | + */ | |
| 295 | + 'showActivity' => __( 'Show AI activity', 'charitable' ), | |
| 296 | + 'hideActivity' => __( 'Hide AI activity', 'charitable' ), | |
| 297 | + ), | |
| 298 | + ) | |
| 299 | + ); | |
| 300 | + } | |
| 301 | +); | |
| 302 | + | |
| 303 | +/** | |
| 304 | + * AJAX: flip the AI write gate. | |
| 305 | + * | |
| 306 | + * No _nopriv counterpart, deliberately - this changes a security setting. | |
| 307 | + * | |
| 308 | + * @since 1.8.13 | |
| 309 | + */ | |
| 310 | +add_action( | |
| 311 | + 'wp_ajax_charitable_ai_mcp_toggle_write', | |
| 312 | + array( Charitable_Tools_AI_MCP::get_instance(), 'ajax_toggle_write' ) | |
| 313 | +); | |
| 314 | + | |
| 315 | +/** | |
| 316 | + * Remember when a user has opened WPVibe's own admin page. | |
| 317 | + * | |
| 318 | + * On `current_screen`, and NOT gated to the Tools tab, because WPVibe's page is | |
| 319 | + * a different screen entirely and the visit has to be caught wherever it | |
| 320 | + * happens. Flips the AI MCP tab's primary button from "Open WPVibe Setup" to | |
| 321 | + * "Go to WPVibe" so a user is not told to set up something they have already | |
| 322 | + * opened. The write is a one-time latch (see maybe_mark_bridge_visited()), so | |
| 323 | + * this costs a single user-meta read on other admin screens. | |
| 324 | + * | |
| 325 | + * @since 1.8.13 | |
| 326 | + */ | |
| 327 | +add_action( | |
| 328 | + 'current_screen', | |
| 329 | + array( Charitable_Tools_AI_MCP::get_instance(), 'maybe_mark_bridge_visited' ) | |
| 330 | +); | |