PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
charitable / includes / admin / tools / views / ai-mcp-activity.php

ai-mcp-activity.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at includes/admin/tools/views/ai-mcp-activity.php

169 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The AI Activity panel on Charitable > Tools > AI MCP.
4 *
5 * A view over the log records Charitable_Abilities_Registrar already writes -
6 * no new storage. Included from
7 * Charitable_Tools_AI_MCP::render_activity_panel(), which prepares every
8 * variable below; this file only renders them.
9 *
10 * Two honesty notes are load-bearing, not decoration, and both are required
11 * to render verbatim rather than be paraphrased:
12 *
13 * - Reads are never logged by default (Charitable_Abilities_Registrar::
14 * log_read() is opt-in), so this panel can only ever show changes and
15 * refusals, never a full activity trail. Said in the description text below
16 * on every state, including the empty one.
17 * - Denial logging depends on `wp_ability_invoked`, core @since 7.1.0. Below
18 * that version writes and refusals still log, but a denial never fires, so
19 * $observation_complete gates a second notice that says so rather than
20 * letting an empty denial column read as "nothing was ever denied".
21 *
22 * @package Charitable/Admin View/Tools
23 * @copyright Copyright (c) 2026, WP Charitable LLC
24 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
25 * @since 1.8.13
26 *
27 * @var array<int,array<string,string>> $rows get_activity_rows()'s return: up to 25 rows, most recent first.
28 * @var bool $observation_complete False on WordPress below 7.1, where denials cannot be recorded at all.
29 * @var array<string,array<string,string>> $clients Active MCP client plugins, from Charitable_Abilities::get_active_mcp_clients().
30 * @var string $logs_url The filtered Tools > Logs URL this panel links out to.
31 */
32
33 // Exit if accessed directly.
34 if ( ! defined( 'ABSPATH' ) ) {
35 exit;
36 }
37
38 $charitable_ai_outcome_labels = array(
39 'applied' => __( 'Applied', 'charitable' ),
40 'refused' => __( 'Refused', 'charitable' ),
41 'denied' => __( 'Denied', 'charitable' ),
42 );
43 ?>
44 <div class="charitable-ai-activity charitable-ai-activity-collapsible is-collapsed">
45
46 <header class="charitable-ai-activity-head">
47 <h3 class="charitable-ai-activity-title"><?php esc_html_e( 'AI Activity', 'charitable' ); ?></h3>
48
49 <?php if ( ! empty( $clients ) ) : ?>
50 <p class="charitable-ai-activity-client">
51 <?php
52 printf(
53 /* translators: %s: comma-separated list of active MCP client plugin names, e.g. "WPVibe". */
54 esc_html__( 'Connected via: %s', 'charitable' ),
55 esc_html( implode( ', ', wp_list_pluck( $clients, 'label' ) ) )
56 );
57 ?>
58 </p>
59 <?php endif; ?>
60
61 <?php
62 /*
63 * A real <button> with aria-expanded rather than an <a href="#">, which
64 * is what the dashboard's equivalent toggle uses. This panel can run to
65 * 25 rows and is collapsed on load, so the control is the only way to
66 * reach the content and has to be announced correctly.
67 *
68 * The arrow is a dashicon, not the dashboard's `fa fa-angle-down`:
69 * Font Awesome is not enqueued on this tab (see
70 * charitable-tools-admin-hooks.php, which loads only this screen's own
71 * CSS and JS), and every other icon on this screen is already a
72 * dashicon. arrow-down-alt2 is the same downward chevron shape, so it
73 * reads as the same affordance without pulling in a whole icon font.
74 *
75 * `is-collapsed` is set in the markup rather than applied by JS on load,
76 * so the table is never painted and then hidden - no flash of the very
77 * content we are collapsing.
78 */
79 ?>
80 <button
81 type="button"
82 class="charitable-ai-activity-toggle"
83 aria-expanded="false"
84 aria-controls="charitable-ai-activity-content"
85 >
86 <span class="screen-reader-text"><?php esc_html_e( 'Show AI activity', 'charitable' ); ?></span>
87 <span class="charitable-ai-activity-angle dashicons dashicons-arrow-right-alt2" aria-hidden="true"></span>
88 </button>
89 </header>
90
91 <div class="charitable-ai-activity-content" id="charitable-ai-activity-content">
92
93 <p class="description charitable-ai-activity-note">
94 <?php esc_html_e( 'Reads are not recorded. This list shows changes an assistant made and anything it was refused.', 'charitable' ); ?>
95 </p>
96
97 <?php if ( ! $observation_complete ) : ?>
98 <p class="description charitable-ai-activity-note">
99 <?php esc_html_e( 'Refused and denied requests are recorded on WordPress 7.1 and later. This site runs an earlier version, so only completed changes appear.', 'charitable' ); ?>
100 </p>
101 <?php endif; ?>
102
103 <?php if ( empty( $rows ) ) : ?>
104
105 <div class="charitable-ai-activity-empty">
106 <p class="charitable-ai-activity-empty-title"><?php esc_html_e( 'Nothing has used this yet.', 'charitable' ); ?></p>
107 <p class="charitable-ai-activity-empty-sub"><?php esc_html_e( 'Once an assistant makes a change, or is refused one, it will show up here.', 'charitable' ); ?></p>
108 </div>
109
110 <?php else : ?>
111
112 <div class="charitable-ai-activity-table-wrap">
113 <table class="charitable-ai-activity-table">
114 <thead>
115 <tr>
116 <th scope="col"><?php esc_html_e( 'Date', 'charitable' ); ?></th>
117 <th scope="col"><?php esc_html_e( 'Ability', 'charitable' ); ?></th>
118 <th scope="col"><?php esc_html_e( 'User', 'charitable' ); ?></th>
119 <th scope="col"><?php esc_html_e( 'Outcome', 'charitable' ); ?></th>
120 <th scope="col"><?php esc_html_e( 'Details', 'charitable' ); ?></th>
121 </tr>
122 </thead>
123 <tbody>
124 <?php foreach ( $rows as $charitable_ai_row ) : ?>
125 <?php
126 $charitable_ai_outcome = isset( $charitable_ai_row['outcome'] ) ? (string) $charitable_ai_row['outcome'] : '';
127 $charitable_ai_label = isset( $charitable_ai_outcome_labels[ $charitable_ai_outcome ] )
128 ? $charitable_ai_outcome_labels[ $charitable_ai_outcome ]
129 : $charitable_ai_outcome;
130 ?>
131 <tr>
132 <td class="charitable-ai-activity-col-date"><?php echo esc_html( $charitable_ai_row['date'] ); ?></td>
133 <td class="charitable-ai-activity-col-ability"><code><?php echo esc_html( $charitable_ai_row['ability'] ); ?></code></td>
134 <td class="charitable-ai-activity-col-user"><?php echo esc_html( $charitable_ai_row['user'] ); ?></td>
135 <td class="charitable-ai-activity-col-outcome">
136 <span class="charitable-ai-outcome charitable-ai-outcome-<?php echo esc_attr( $charitable_ai_outcome ); ?>">
137 <?php echo esc_html( $charitable_ai_label ); ?>
138 </span>
139 </td>
140 <td class="charitable-ai-activity-col-message"><?php echo esc_html( wp_strip_all_tags( $charitable_ai_row['message'] ) ); ?></td>
141 </tr>
142 <?php endforeach; ?>
143 </tbody>
144 </table>
145 </div>
146
147 <?php endif; ?>
148
149 </div><!-- /.charitable-ai-activity-content -->
150
151 <?php
152 /*
153 * OUTSIDE the collapsing region, deliberately. Collapsed is the default
154 * state, and the route to the full log has to stay reachable in it - a
155 * panel that hides both its rows AND the way to see more rows is a dead
156 * end. This is also the one link that still means something when there are
157 * no rows at all, since Tools > Logs holds the history this panel only
158 * summarises.
159 */
160 ?>
161 <p class="charitable-ai-activity-more">
162 <a href="<?php echo esc_url( $logs_url ); ?>">
163 <?php esc_html_e( 'View full history at Tools > Logs', 'charitable' ); ?>
164 <span aria-hidden="true">&rarr;</span>
165 </a>
166 </p>
167
168 </div>
169