PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.2
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.2
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / admin / class-lp-admin-mcp-api-keys-table-list.php

class-lp-admin-mcp-api-keys-table-list.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.2, at inc/admin/class-lp-admin-mcp-api-keys-table-list.php

249 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use LearnPress\MCP\Auth\ApiKeysRepository;
4
5 defined( 'ABSPATH' ) || exit;
6
7 if ( ! class_exists( 'WP_List_Table' ) ) {
8 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
9 }
10
11 /**
12 * Admin table for LearnPress MCP API keys.
13 */
14 class LP_Admin_MCP_API_Keys_Table_List extends WP_List_Table {
15 /**
16 * @var ApiKeysRepository
17 */
18 protected $repository;
19
20 /**
21 * @var array<int, object>
22 */
23 protected $users_with_keys = array();
24
25 /**
26 * Initialize list-table with MCP keys repository dependency.
27 *
28 * @param ApiKeysRepository $repository Repository for querying and mutating key records.
29 *
30 * @return void
31 */
32 public function __construct( ApiKeysRepository $repository ) {
33 $this->repository = $repository;
34
35 parent::__construct(
36 array(
37 'singular' => 'lp_mcp_api_key',
38 'plural' => 'lp_mcp_api_keys',
39 'ajax' => false,
40 )
41 );
42 }
43
44 /**
45 * Define visible columns for MCP API key table.
46 *
47 * @return array<string, string>
48 */
49 public function get_columns() {
50 return array(
51 'cb' => '<input type="checkbox" />',
52 'description' => esc_html__( 'Description', 'learnpress' ),
53 'key_ending' => esc_html__( 'Key Ending', 'learnpress' ),
54 'user' => esc_html__( 'User', 'learnpress' ),
55 'permissions' => esc_html__( 'Permissions', 'learnpress' ),
56 'last_access' => esc_html__( 'Last Access', 'learnpress' ),
57 'call_count' => esc_html__( 'Calls', 'learnpress' ),
58 );
59 }
60
61 /**
62 * Define sortable columns and default sort directions.
63 *
64 * @return array<string, array{0:string,1:bool}>
65 */
66 protected function get_sortable_columns() {
67 return array(
68 'description' => array( 'description', false ),
69 'user' => array( 'user', false ),
70 'permissions' => array( 'permissions', false ),
71 'last_access' => array( 'last_access', true ),
72 'call_count' => array( 'call_count', true ),
73 );
74 }
75
76 /**
77 * Define supported bulk actions for selected keys.
78 *
79 * @return array<string, string>
80 */
81 protected function get_bulk_actions() {
82 return array(
83 'bulk-revoke' => esc_html__( 'Revoke', 'learnpress' ),
84 );
85 }
86
87 /**
88 * Render row checkbox used by bulk actions.
89 *
90 * @param object $item Current key row object.
91 *
92 * @return string
93 */
94 protected function column_cb( $item ) {
95 return sprintf( '<input type="checkbox" name="key_ids[]" value="%d" />', absint( $item->key_id ) );
96 }
97
98 /**
99 * Render description column with inline row actions.
100 *
101 * Row actions include revoke link.
102 *
103 * @param object $item Current key row object.
104 *
105 * @return string
106 */
107 protected function column_description( $item ) {
108 $description = $item->description ? $item->description : esc_html__( '(No description)', 'learnpress' );
109
110 $base_url = add_query_arg(
111 array(
112 'page' => 'learn-press-settings',
113 'tab' => 'advanced',
114 'section' => 'mcp',
115 ),
116 admin_url( 'admin.php' )
117 );
118 $revoke_url = wp_nonce_url(
119 add_query_arg(
120 array(
121 'lp_mcp_key_action' => 'revoke',
122 'key_id' => absint( $item->key_id ),
123 ),
124 $base_url
125 ),
126 'lp_mcp_revoke_key_' . absint( $item->key_id )
127 );
128
129 $actions = array(
130 'revoke' => sprintf(
131 '<a href="%s" onclick="return confirm(\'%s\');">%s</a>',
132 esc_url( $revoke_url ),
133 esc_js( __( 'Revoke this API key?', 'learnpress' ) ),
134 esc_html__( 'Revoke', 'learnpress' )
135 ),
136 );
137
138 return sprintf( '%1$s %2$s', esc_html( $description ), $this->row_actions( $actions ) );
139 }
140
141 /**
142 * Render non-custom columns by column key.
143 *
144 * @param object $item Current key row object.
145 * @param string $column_name Current column key.
146 *
147 * @return string
148 */
149 protected function column_default( $item, $column_name ) {
150 switch ( $column_name ) {
151 case 'key_ending':
152 return '...' . esc_html( (string) $item->truncated_key );
153 case 'user':
154 $name = $item->user_display_name ?: $item->user_login;
155 if ( ! $name ) {
156 $name = esc_html__( '(Missing user)', 'learnpress' );
157 }
158
159 return esc_html( $name );
160 case 'permissions':
161 return esc_html( (string) $item->permissions );
162 case 'last_access':
163 if ( empty( $item->last_access ) ) {
164 return '&mdash;';
165 }
166
167 return esc_html( get_date_from_gmt( (string) $item->last_access, 'Y-m-d H:i:s' ) );
168 case 'call_count':
169 return esc_html( (string) absint( $item->call_count ) );
170 }
171
172 return '';
173 }
174
175 /**
176 * Render extra controls above table: user filter dropdown.
177 *
178 * @param string $which Table position (`top` or `bottom`).
179 *
180 * @return void
181 */
182 protected function extra_tablenav( $which ) {
183 if ( 'top' !== $which ) {
184 return;
185 }
186
187 $user_filter = absint( $_REQUEST['mcp_user_id'] ?? 0 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
188
189 echo '<div class="alignleft actions">';
190 echo '<label class="screen-reader-text" for="mcp_user_id">' . esc_html__( 'Filter by user', 'learnpress' ) . '</label>';
191 echo '<select id="mcp_user_id" name="mcp_user_id">';
192 echo '<option value="0">' . esc_html__( 'All users', 'learnpress' ) . '</option>';
193
194 foreach ( $this->users_with_keys as $user ) {
195 echo '<option value="' . esc_attr( $user->ID ) . '" ' . selected( $user_filter, absint( $user->ID ), false ) . '>' . esc_html( $user->display_name ) . '</option>';
196 }
197
198 echo '</select>';
199
200 submit_button( __( 'Filter', 'learnpress' ), 'button', 'filter_action', false );
201 echo '</div>';
202 }
203
204 /**
205 * Query and prepare list-table items and pagination metadata.
206 *
207 * @return void
208 */
209 public function prepare_items() {
210 $search = sanitize_text_field( wp_unslash( $_REQUEST['s'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
211 $user_id = absint( $_REQUEST['mcp_user_id'] ?? 0 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
212 $orderby = sanitize_key( $_REQUEST['orderby'] ?? 'created_at' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
213 $order = sanitize_key( $_REQUEST['order'] ?? 'desc' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
214 $page_num = $this->get_pagenum();
215
216 $results = $this->repository->query_keys(
217 array(
218 'page' => $page_num,
219 'per_page' => 20,
220 'search' => $search,
221 'user_id' => $user_id,
222 'orderby' => $orderby,
223 'order' => $order,
224 )
225 );
226
227 $this->items = $results['items'];
228 $this->users_with_keys = $this->repository->users_with_keys();
229
230 $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
231
232 $this->set_pagination_args(
233 array(
234 'total_items' => $results['total'],
235 'per_page' => 20,
236 )
237 );
238 }
239
240 /**
241 * Render empty state when no keys match current filters.
242 *
243 * @return void
244 */
245 public function no_items() {
246 echo esc_html__( 'No MCP API keys found.', 'learnpress' );
247 }
248 }
249