Changeset 3466413
- Timestamp:
- 02/21/2026 01:58:37 PM (5 weeks ago)
- Location:
- some-plus-report-post/trunk
- Files:
-
- 4 edited
-
assets/css/admin.css (modified) (2 diffs)
-
assets/js/admin.js (modified) (2 diffs)
-
includes/class-ajax.php (modified) (2 diffs)
-
includes/class-reports-list-table.php (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
some-plus-report-post/trunk/assets/css/admin.css
r3433075 r3466413 106 106 /* Table Enhancements */ 107 107 .wp-list-table .column-post_title { 108 width: 2 5%;108 width: 23%; 109 109 } 110 110 … … 130 130 } 131 131 132 .wp-list-table .column-report_reason { 133 width: 12%; 134 } 135 132 136 .wp-list-table .column-last_report { 133 width: 15%; 137 width: 12%; 138 } 139 140 /* Report Reason Styles */ 141 .sprp-reason { 142 display: inline-block; 143 padding: 3px 8px; 144 background: #f0f6fc; 145 border: 1px solid #c5d9ed; 146 border-radius: 3px; 147 font-size: 12px; 148 color: #1d2327; 149 cursor: help; 150 } 151 152 /* View Details Link */ 153 .sprp-view-details { 154 color: #2271b1; 155 text-decoration: underline; 156 } 157 158 .sprp-view-details:hover { 159 color: #135e96; 160 } 161 162 /* Modal Styles */ 163 .sprp-modal-overlay { 164 position: fixed; 165 top: 0; 166 left: 0; 167 right: 0; 168 bottom: 0; 169 background: rgba(0, 0, 0, 0.5); 170 z-index: 100000; 171 } 172 173 .sprp-modal { 174 position: fixed; 175 top: 50%; 176 left: 50%; 177 transform: translate(-50%, -50%); 178 background: #fff; 179 border-radius: 4px; 180 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); 181 z-index: 100001; 182 max-width: 900px; 183 width: 90%; 184 max-height: 80vh; 185 display: flex; 186 flex-direction: column; 187 } 188 189 .sprp-modal-header { 190 padding: 15px 20px; 191 border-bottom: 1px solid #c3c4c7; 192 display: flex; 193 justify-content: space-between; 194 align-items: center; 195 } 196 197 .sprp-modal-header h2 { 198 margin: 0; 199 font-size: 18px; 200 } 201 202 .sprp-modal-close { 203 background: none; 204 border: none; 205 font-size: 24px; 206 cursor: pointer; 207 color: #646970; 208 padding: 0; 209 width: 30px; 210 height: 30px; 211 line-height: 30px; 212 } 213 214 .sprp-modal-close:hover { 215 color: #1d2327; 216 } 217 218 .sprp-modal-content { 219 padding: 20px; 220 overflow-y: auto; 221 flex: 1; 222 } 223 224 .sprp-report-details-table { 225 width: 100%; 226 border-collapse: collapse; 227 } 228 229 .sprp-report-details-table th, 230 .sprp-report-details-table td { 231 padding: 10px; 232 text-align: left; 233 border-bottom: 1px solid #c3c4c7; 234 } 235 236 .sprp-report-details-table th { 237 background: #f6f7f7; 238 font-weight: 600; 239 } 240 241 .sprp-report-details-table tr:hover { 242 background: #f6f7f7; 134 243 } 135 244 -
some-plus-report-post/trunk/assets/js/admin.js
r3433075 r3466413 32 32 $('#sprp-add-reason').on('click', this.handleAddReason); 33 33 $(document).on('click', '.sprp-remove-reason', this.handleRemoveReason); 34 35 // View report details. 36 $(document).on('click', '.sprp-view-details', this.handleViewDetails); 37 38 // Close modal. 39 $(document).on('click', '.sprp-modal-close, .sprp-modal-overlay', this.handleCloseModal); 40 $(document).on('keydown', this.handleEscKey); 34 41 }, 35 42 … … 125 132 126 133 return true; 134 }, 135 136 /** 137 * Handle view details click. 138 * 139 * @param {Event} e Click event. 140 */ 141 handleViewDetails: function(e) { 142 e.preventDefault(); 143 144 var $link = $(this); 145 var postId = $link.data('post-id'); 146 147 // Show loading state. 148 $link.text('Loading...'); 149 150 // Fetch report details via AJAX. 151 $.ajax({ 152 url: sprpAdmin.ajaxUrl, 153 type: 'POST', 154 data: { 155 action: 'sprp_get_report_details', 156 nonce: sprpAdmin.nonce, 157 post_id: postId 158 }, 159 success: function(response) { 160 $link.text('Details'); 161 if (response.success) { 162 SprpAdmin.showReportModal(response.data); 163 } else { 164 alert(response.data.message || 'An error occurred.'); 165 } 166 }, 167 error: function() { 168 $link.text('Details'); 169 alert('Failed to load report details.'); 170 } 171 }); 172 }, 173 174 /** 175 * Show report details modal. 176 * 177 * @param {Object} data Report data. 178 */ 179 showReportModal: function(data) { 180 // Remove existing modal. 181 $('.sprp-modal').remove(); 182 183 var reports = data.reports; 184 var html = '<div class="sprp-modal-overlay"></div>' + 185 '<div class="sprp-modal">' + 186 '<div class="sprp-modal-header">' + 187 '<h2>Report Details (' + data.count + ' reports)</h2>' + 188 '<button class="sprp-modal-close">×</button>' + 189 '</div>' + 190 '<div class="sprp-modal-content">' + 191 '<table class="sprp-report-details-table">' + 192 '<thead>' + 193 '<tr>' + 194 '<th>Date</th>' + 195 '<th>Reason</th>' + 196 '<th>User</th>' + 197 '<th>Additional Info</th>' + 198 '<th>Status</th>' + 199 '</tr>' + 200 '</thead>' + 201 '<tbody>'; 202 203 for (var i = 0; i < reports.length; i++) { 204 var report = reports[i]; 205 html += '<tr>' + 206 '<td>' + report.date + '</td>' + 207 '<td><strong>' + report.reason + '</strong></td>' + 208 '<td>' + report.user + '</td>' + 209 '<td>' + (report.reason_text ? report.reason_text : '-') + '</td>' + 210 '<td><span class="sprp-status status-' + report.status + '">' + report.status + '</span></td>' + 211 '</tr>'; 212 } 213 214 html += '</tbody></table></div></div>'; 215 216 $('body').append(html); 217 }, 218 219 /** 220 * Handle close modal. 221 * 222 * @param {Event} e Click event. 223 */ 224 handleCloseModal: function(e) { 225 e.preventDefault(); 226 $('.sprp-modal, .sprp-modal-overlay').remove(); 227 }, 228 229 /** 230 * Handle ESC key to close modal. 231 * 232 * @param {Event} e Keydown event. 233 */ 234 handleEscKey: function(e) { 235 if (e.keyCode === 27) { 236 $('.sprp-modal, .sprp-modal-overlay').remove(); 237 } 127 238 } 128 239 }; -
some-plus-report-post/trunk/includes/class-ajax.php
r3433075 r3466413 30 30 // Admin AJAX handlers. 31 31 add_action( 'wp_ajax_sprp_admin_action', array( $this, 'admin_action' ) ); 32 add_action( 'wp_ajax_sprp_get_report_details', array( $this, 'get_report_details' ) ); 32 33 } 33 34 … … 170 171 171 172 /** 173 * Get report details for a post. 174 */ 175 public function get_report_details() { 176 // Verify nonce. 177 if ( ! check_ajax_referer( 'sprp_admin_nonce', 'nonce', false ) ) { 178 wp_send_json_error( 179 array( 180 'message' => __( 'Security check failed.', 'some-plus-report-post' ), 181 ) 182 ); 183 } 184 185 // Check capabilities. 186 if ( ! current_user_can( 'manage_options' ) ) { 187 wp_send_json_error( 188 array( 189 'message' => __( 'You do not have permission to perform this action.', 'some-plus-report-post' ), 190 ) 191 ); 192 } 193 194 $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0; 195 196 if ( ! $post_id ) { 197 wp_send_json_error( 198 array( 199 'message' => __( 'Invalid post ID.', 'some-plus-report-post' ), 200 ) 201 ); 202 } 203 204 global $wpdb; 205 $table_name = SomePlusReportPost::get_table_name(); 206 $reasons = SomePlusReportPost::get_reasons(); 207 208 // Get all reports for this post. 209 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 210 $reports = $wpdb->get_results( 211 $wpdb->prepare( 212 "SELECT 213 user_id, 214 user_ip, 215 reason_id, 216 reason_text, 217 status, 218 created_at 219 FROM {$table_name} 220 WHERE post_id = %d 221 ORDER BY created_at DESC", 222 $post_id 223 ), 224 ARRAY_A 225 ); 226 227 if ( empty( $reports ) ) { 228 wp_send_json_error( 229 array( 230 'message' => __( 'No reports found for this post.', 'some-plus-report-post' ), 231 ) 232 ); 233 } 234 235 // Format reports for display. 236 $formatted_reports = array(); 237 foreach ( $reports as $report ) { 238 $user_info = ''; 239 if ( ! empty( $report['user_id'] ) ) { 240 $user = get_userdata( $report['user_id'] ); 241 $user_info = $user ? $user->display_name : __( 'Unknown User', 'some-plus-report-post' ); 242 } else { 243 $user_info = __( 'Guest (IP: ', 'some-plus-report-post' ) . esc_html( $report['user_ip'] ) . ')'; 244 } 245 246 $reason_label = isset( $reasons[ $report['reason_id'] ] ) 247 ? $reasons[ $report['reason_id'] ] 248 : __( 'Unknown', 'some-plus-report-post' ); 249 250 $formatted_reports[] = array( 251 'user' => $user_info, 252 'reason' => $reason_label, 253 'reason_text' => ! empty( $report['reason_text'] ) ? $report['reason_text'] : '', 254 'status' => $report['status'], 255 'date' => mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $report['created_at'] ), 256 ); 257 } 258 259 wp_send_json_success( 260 array( 261 'reports' => $formatted_reports, 262 'count' => count( $formatted_reports ), 263 ) 264 ); 265 } 266 267 /** 172 268 * Handle admin actions via AJAX. 173 269 */ -
some-plus-report-post/trunk/includes/class-reports-list-table.php
r3433075 r3466413 51 51 'post_date' => __( 'Post Date', 'some-plus-report-post' ), 52 52 'post_status' => __( 'Status', 'some-plus-report-post' ), 53 'report_reason' => __( 'Report Reason', 'some-plus-report-post' ), 53 54 'reports_count' => __( 'Reports', 'some-plus-report-post' ), 54 55 'last_report' => __( 'Last Report', 'some-plus-report-post' ), … … 65 66 'post_title' => array( 'post_title', false ), 66 67 'post_date' => array( 'post_date', false ), 68 'report_reason' => array( 'report_reason', false ), 67 69 'reports_count' => array( 'reports_count', true ), 68 70 'last_report' => array( 'last_report', true ), … … 190 192 $order = isset( $_REQUEST['order'] ) ? sanitize_key( $_REQUEST['order'] ) : 'DESC'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended 191 193 192 $allowed_orderby = array( 'post_title', 'post_date', 'reports_count', 'last_report' );194 $allowed_orderby = array( 'post_title', 'post_date', 'reports_count', 'last_report', 'report_reason' ); 193 195 $orderby = in_array( $orderby, $allowed_orderby, true ) ? $orderby : 'reports_count'; 194 196 $order = in_array( strtoupper( $order ), array( 'ASC', 'DESC' ), true ) ? strtoupper( $order ) : 'DESC'; … … 200 202 'reports_count' => 'reports_count', 201 203 'last_report' => 'last_report', 204 'report_reason' => 'report_reason', 202 205 ); 203 206 $orderby_sql = $orderby_map[ $orderby ]; … … 225 228 p.post_status, 226 229 COUNT(r.id) as reports_count, 227 MAX(r.created_at) as last_report 230 MAX(r.created_at) as last_report, 231 GROUP_CONCAT(DISTINCT r.reason_id ORDER BY r.reason_id ASC SEPARATOR ',') as report_reasons 228 232 FROM {$table_name} r 229 233 INNER JOIN {$wpdb->posts} p ON r.post_id = p.ID … … 429 433 430 434 /** 435 * Render report reason column. 436 * 437 * @param array $item Item data. 438 * @return string 439 */ 440 public function column_report_reason( $item ) { 441 if ( empty( $item['report_reasons'] ) ) { 442 return '—'; 443 } 444 445 $reasons = SomePlusReportPost::get_reasons(); 446 $reason_ids = explode( ',', $item['report_reasons'] ); 447 $reason_labels = array(); 448 449 foreach ( $reason_ids as $reason_id ) { 450 if ( isset( $reasons[ $reason_id ] ) ) { 451 $reason_labels[] = esc_html( $reasons[ $reason_id ] ); 452 } 453 } 454 455 if ( empty( $reason_labels ) ) { 456 return '—'; 457 } 458 459 // Create a tooltip with all reasons. 460 $tooltip = implode( ', ', $reason_labels ); 461 462 // Show first reason + count if multiple. 463 $display = $reason_labels[0]; 464 if ( count( $reason_labels ) > 1 ) { 465 $display .= ' +' . ( count( $reason_labels ) - 1 ); 466 } 467 468 return sprintf( 469 '<span class="sprp-reason" title="%s">%s</span>', 470 esc_attr( $tooltip ), 471 esc_html( $display ) 472 ); 473 } 474 475 /** 431 476 * Render reports count column. 432 477 * … … 436 481 public function column_reports_count( $item ) { 437 482 $count = absint( $item['reports_count'] ); 483 $post_id = absint( $item['post_id'] ); 438 484 439 485 // Add visual indicator for high report counts. … … 445 491 } 446 492 493 // Add view details link. 494 $details_link = sprintf( 495 '<a href="#" class="sprp-view-details" data-post-id="%d">%s</a>', 496 $post_id, 497 esc_html__( 'Details', 'some-plus-report-post' ) 498 ); 499 447 500 return sprintf( 448 '<span class="reports-count %s">%s</span> ',501 '<span class="reports-count %s">%s</span><br><small>%s</small>', 449 502 esc_attr( $class ), 450 esc_html( number_format_i18n( $count ) ) 503 esc_html( number_format_i18n( $count ) ), 504 $details_link 451 505 ); 452 506 }
Note: See TracChangeset
for help on using the changeset viewer.