PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 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 All 140 releases
← All changes | inc/admin/class-lp-admin-mcp-api-keys-table-list.php +248 -248 4.3.8 → 4.4.9 View file →
@@ -1,248 +1,248 @@
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' => 'mcp',
114 - ),
115 - admin_url( 'admin.php' )
116 - );
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 -}
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 +}