Plugin Directory

Changeset 3466413


Ignore:
Timestamp:
02/21/2026 01:58:37 PM (5 weeks ago)
Author:
someplus
Message:

Version 1.1.0 update

Location:
some-plus-report-post/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • some-plus-report-post/trunk/assets/css/admin.css

    r3433075 r3466413  
    106106/* Table Enhancements */
    107107.wp-list-table .column-post_title {
    108     width: 25%;
     108    width: 23%;
    109109}
    110110
     
    130130}
    131131
     132.wp-list-table .column-report_reason {
     133    width: 12%;
     134}
     135
    132136.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;
    134243}
    135244
  • some-plus-report-post/trunk/assets/js/admin.js

    r3433075 r3466413  
    3232            $('#sprp-add-reason').on('click', this.handleAddReason);
    3333            $(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);
    3441        },
    3542
     
    125132
    126133            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">&times;</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            }
    127238        }
    128239    };
  • some-plus-report-post/trunk/includes/class-ajax.php

    r3433075 r3466413  
    3030        // Admin AJAX handlers.
    3131        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' ) );
    3233    }
    3334
     
    170171
    171172    /**
     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    /**
    172268     * Handle admin actions via AJAX.
    173269     */
  • some-plus-report-post/trunk/includes/class-reports-list-table.php

    r3433075 r3466413  
    5151            'post_date'     => __( 'Post Date', 'some-plus-report-post' ),
    5252            'post_status'   => __( 'Status', 'some-plus-report-post' ),
     53            'report_reason' => __( 'Report Reason', 'some-plus-report-post' ),
    5354            'reports_count' => __( 'Reports', 'some-plus-report-post' ),
    5455            'last_report'   => __( 'Last Report', 'some-plus-report-post' ),
     
    6566            'post_title'    => array( 'post_title', false ),
    6667            'post_date'     => array( 'post_date', false ),
     68            'report_reason' => array( 'report_reason', false ),
    6769            'reports_count' => array( 'reports_count', true ),
    6870            'last_report'   => array( 'last_report', true ),
     
    190192        $order   = isset( $_REQUEST['order'] ) ? sanitize_key( $_REQUEST['order'] ) : 'DESC'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    191193
    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' );
    193195        $orderby         = in_array( $orderby, $allowed_orderby, true ) ? $orderby : 'reports_count';
    194196        $order           = in_array( strtoupper( $order ), array( 'ASC', 'DESC' ), true ) ? strtoupper( $order ) : 'DESC';
     
    200202            'reports_count' => 'reports_count',
    201203            'last_report'   => 'last_report',
     204            'report_reason' => 'report_reason',
    202205        );
    203206        $orderby_sql = $orderby_map[ $orderby ];
     
    225228                    p.post_status,
    226229                    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
    228232                FROM {$table_name} r
    229233                INNER JOIN {$wpdb->posts} p ON r.post_id = p.ID
     
    429433
    430434    /**
     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 '&mdash;';
     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 '&mdash;';
     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    /**
    431476     * Render reports count column.
    432477     *
     
    436481    public function column_reports_count( $item ) {
    437482        $count = absint( $item['reports_count'] );
     483        $post_id = absint( $item['post_id'] );
    438484
    439485        // Add visual indicator for high report counts.
     
    445491        }
    446492
     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
    447500        return sprintf(
    448             '<span class="reports-count %s">%s</span>',
     501            '<span class="reports-count %s">%s</span><br><small>%s</small>',
    449502            esc_attr( $class ),
    450             esc_html( number_format_i18n( $count ) )
     503            esc_html( number_format_i18n( $count ) ),
     504            $details_link
    451505        );
    452506    }
Note: See TracChangeset for help on using the changeset viewer.