@@ -24,6 +24,20 @@ class ViewLogsPage {
2424 */
2525 public const ADMIN_PAGE_SLUG = 'wpgraphql-logging-view ' ;
2626
27+ /**
28+ * The nonce for the view page.
29+ *
30+ * @var string
31+ */
32+ public const ADMIN_PAGE_VIEW_NONCE = 'wp_graphql_logging_admin ' ;
33+
34+ /**
35+ * The nonce for the download page.
36+ *
37+ * @var string
38+ */
39+ public const ADMIN_PAGE_DOWNLOAD_NONCE = 'wp_graphql_logging_download ' ;
40+
2741 /**
2842 * The hook suffix for the admin page.
2943 *
@@ -124,36 +138,33 @@ public function enqueue_admin_scripts( string $hook_suffix ): void {
124138
125139 wp_enqueue_style ( 'jquery-ui-style ' , 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css ' , [], '1.12.1 ' );
126140
127- // Add inline script to initialize the datetimepicker.
128- wp_add_inline_script (
129- 'jquery-ui-timepicker-addon ' ,
130- 'jQuery(document).ready(function($){ $(".wpgraphql-logging-datepicker").datetimepicker({ dateFormat: "yy-mm-dd", timeFormat: "HH:mm:ss" }); }); '
131- );
132-
133- // Add nonce to sorting links.
134- wp_add_inline_script (
135- 'jquery ' ,
136- 'jQuery(document).ready(function($){
137- var nonce = $("#wpgraphql-logging-sort-nonce").val();
138- if ( nonce ) {
139- $("th.sortable a").each(function(){
140- this.href = this.href + "&_wpnonce=" + nonce;
141- });
142- }
143- }); '
144- );
141+ // Enqueue admin scripts if they exist.
142+ $ script_path = trailingslashit ( WPGRAPHQL_LOGGING_PLUGIN_URL ) . 'assets/js/settings/wp-graphql-logging-view.js ' ;
143+ if ( file_exists ( trailingslashit ( WPGRAPHQL_LOGGING_PLUGIN_DIR ) . 'assets/js/settings/wp-graphql-logging-view.js ' ) ) {
144+ wp_enqueue_script (
145+ 'wpgraphql-logging-view-js ' ,
146+ $ script_path ,
147+ [ 'jquery ' ],
148+ WPGRAPHQL_LOGGING_VERSION ,
149+ true
150+ );
151+ }
145152
146153 // Allow other plugins to enqueue their own scripts/styles.
147154 do_action ( 'wpgraphql_logging_view_logs_admin_enqueue_scripts ' , $ hook_suffix );
148155 }
149156
150157 /**
151158 * Renders the admin page for the logs.
159+ *
160+ * @phpcs:disable WordPress.Security.NonceVerification.Recommended
152161 */
153162 public function render_admin_page (): void {
163+
164+
154165 $ action = isset ( $ _REQUEST ['action ' ] ) && is_string ( $ _REQUEST ['action ' ] )
155166 ? sanitize_text_field ( $ _REQUEST ['action ' ] )
156- : 'link ' ; // @phpcs:ignore WordPress.Security.NonceVerification.Recommended
167+ : 'list ' ;
157168
158169 switch ( $ action ) {
159170 case 'view ' :
@@ -173,8 +184,10 @@ public function render_admin_page(): void {
173184 * This runs before any HTML is output.
174185 */
175186 public function process_page_actions_before_rendering (): void {
176- // Check for a download request.
177- if ( isset ( $ _GET ['action ' ] ) && 'download ' === $ _GET ['action ' ] ) { // @phpcs:ignore WordPress.Security.NonceVerification.Recommended
187+
188+ // Nonce handled in process_log_download and process_filters_redirect.
189+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
190+ if ( isset ( $ _GET ['action ' ] ) && 'download ' === $ _GET ['action ' ] ) {
178191 $ this ->process_log_download ();
179192 }
180193
@@ -238,14 +251,16 @@ public function get_redirect_url(): string {
238251 *
239252 * @param string $key The key to retrieve from $_POST.
240253 *
254+ * @phpcs:disable WordPress.Security.NonceVerification.Missing
255+ *
241256 * @return string|null The sanitized value or null if not set or invalid.
242257 */
243258 protected function get_post_value (string $ key ): ?string {
244- $ value = $ _POST [ $ key ] ?? null ; // @phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
245- if ( ! is_string ( $ value ) || '' === $ value ) {
259+ if ( ! array_key_exists ( $ key , $ _POST ) || ! is_string ( $ _POST [ $ key ] ) ) {
246260 return null ;
247261 }
248- return sanitize_text_field ( wp_unslash ( $ value ) );
262+ $ post_value = sanitize_text_field ( wp_unslash ( $ _POST [ $ key ] ) );
263+ return '' !== $ post_value ? $ post_value : null ;
249264 }
250265
251266 /**
@@ -257,17 +272,14 @@ protected function render_list_page(): void {
257272 require_once $ list_template ; // @phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
258273 }
259274
260- /**
261- * Renders the list page for log entries.
262- */
275+ /**
276+ * Renders the list page for log entries.
277+ */
263278 protected function process_log_download (): void {
264- if ( ! current_user_can ( 'manage_options ' ) || ! is_admin () ) {
265- wp_die ( esc_html__ ( 'You do not have sufficient permissions to access this page. ' , 'wpgraphql-logging ' ) );
266- }
267-
268279 $ log_id = isset ( $ _GET ['log ' ] ) ? absint ( $ _GET ['log ' ] ) : 0 ;
269- if ( $ log_id > 0 ) {
270- check_admin_referer ( 'wpgraphql-logging-download_ ' . $ log_id );
280+ $ this ->verify_admin_page_nonce ( self ::ADMIN_PAGE_DOWNLOAD_NONCE . '_ ' . $ log_id );
281+ if ( 0 === (int ) $ log_id ) {
282+ wp_die ( esc_html__ ( 'Invalid log ID. ' , 'wpgraphql-logging ' ) );
271283 }
272284 $ downloader = new DownloadLogService ( $ this ->get_log_service () );
273285 $ downloader ->generate_csv ( $ log_id );
@@ -277,7 +289,8 @@ protected function process_log_download(): void {
277289 * Renders the view page for a single log entry.
278290 */
279291 protected function render_view_page (): void {
280- $ log_id = isset ( $ _GET ['log ' ] ) ? absint ( $ _GET ['log ' ] ) : 0 ; // @phpcs:ignore WordPress.Security.NonceVerification.Recommended
292+ $ log_id = isset ( $ _GET ['log ' ] ) ? absint ( $ _GET ['log ' ] ) : 0 ;
293+ $ this ->verify_admin_page_nonce ( self ::ADMIN_PAGE_DOWNLOAD_NONCE . '_ ' . $ log_id );
281294
282295 if ( 0 === (int ) $ log_id ) {
283296 echo '<div class="notice notice-error"><p> ' . esc_html__ ( 'Invalid log ID. ' , 'wpgraphql-logging ' ) . '</p></div> ' ;
@@ -297,6 +310,18 @@ protected function render_view_page(): void {
297310 require_once $ log_template ; // @phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
298311 }
299312
313+ /**
314+ * Verifies the admin page nonce.
315+ *
316+ * @param string $nonce The nonce to verify.
317+ */
318+ protected function verify_admin_page_nonce (string $ nonce ): void {
319+ if ( ! current_user_can ( 'manage_options ' ) || ! is_admin () ) {
320+ wp_die ( esc_html__ ( 'You do not have sufficient permissions to access this page. ' , 'wpgraphql-logging ' ) );
321+ }
322+ check_admin_referer ( $ nonce );
323+ }
324+
300325 /**
301326 * Retrieves the log service instance.
302327 *
0 commit comments