Plugin Directory

Changeset 3115598

Timestamp:
07/10/2024 12:34:06 PM (4 weeks ago)
Author:
lumiblog
Message:
  • Fixed critical error causing "Division by zero" in log list pagination
  • Improved overall plugin stability and security
  • Enhanced compatibility with latest WordPress version
Location:
wp-blame
Files:
9 added
4 edited

Legend:

Unmodified
Added
Removed
  • wp-blame/trunk/class-log-list.php

    r1815341 r3115598  
    66class WPB_Log_List extends WP_List_Table {
    77
    8     /**
    9      * Initialise the logs table.
    10      *
    11      * @since 2.0
    12      *
    13      * @return void
    14      */
    15     public function __construct() {
    16 
    17         parent::__construct(
    18             array(
    19                 'singular' => __('Log', 'wp-blame'),
    20                 'plural' => __('Logs', 'wp-blame'),
    21                 'ajax' => false
    22             )
    23         );
    24 
    25         $this->prepare_items();
    26 
    27     }
    28 
    29     /**
    30      * Define the table columns.
    31      *
    32      * @since 2.0
    33      *
    34      * @return void
    35      */
    36     public function get_columns() {
    37 
    38         $columns = [
    39             'cb'        => '<input type="checkbox" />',
    40             'log_id'    => __('Log', 'wp-blame'),
    41             'item'      => __('Item', 'wp-blame'),
    42             'action'    => __('Action', 'wp-blame'),
    43             'user_id'   => __('User', 'wp-blame'),
    44             'notes'     => __('Notes', 'wp-blame'),
    45             'timestamp' => __('Date', 'wp-blame')
    46         ];
    47 
    48         return $columns;
    49 
    50     }
    51 
    52     /**
    53      * Set which columns are sortable.
    54      *
    55      * @since 2.0
    56      *
    57      * @return void
    58      */
    59     public function get_sortable_columns() {
    60 
    61         $sortable_columns = array(
    62             'timestamp' => array('timestamp', false)
    63         );
    64 
    65         return $sortable_columns;
    66    
    67     }
    68 
    69     /**
    70      * Return the checkbox column.
    71      *
    72      * @since 2.0
    73      *
    74      * @param object $item Current row item.
    75      *
    76      * @return string
    77      */
    78     public function column_cb( $item ) {
    79        
    80         return sprintf('<input type="checkbox" name="%1$s[]" value="%2$s" />', $this->_args['singular'], $item->log_id );
    81    
    82     }
    83 
    84     /**
    85      * Return the log id column.
    86      *
    87      * @since 2.0
    88      *
    89      * @param object $item Current row item.
    90      *
    91      * @return string
    92      */
    93     public function column_log_id( $item ) {
    94 
    95         return $item->log_id;
    96 
    97     }
    98 
    99     /**
    100      * Return the log type column.
    101      *
    102      * @since 2.0
    103      *
    104      * @param object $item Current row item.
    105      *
    106      * @return string
    107      */
    108     public function column_item( $item ) {
    109 
    110         if ( 'post' == $item->slug ) {
    111 
    112             $name = ! empty( get_the_title( $item->object_id ) ) ? get_the_title( $item->object_id ) : __('Post', 'wp-blame');
    113             $link = esc_url( admin_url('post.php?post=' . $item->object_id . '&action=edit') );
    114 
    115         } elseif ( 'term' == $item->slug ) {
    116 
    117             $term = get_term( $item->object_id );
    118             $name = ! empty( $term->name ) ? $term->name : __('Term', 'wp-blame');
    119             $link = esc_url( admin_url('term.php?tag_ID=' . $item->object_id) );
    120 
    121         } elseif ( 'media' == $item->slug ) {
    122 
    123             $name = ! empty( get_the_title( $item->object_id ) ) ? get_the_title( $item->object_id ) : __('Media', 'wp-blame');
    124             $link = esc_url( admin_url('upload.php?item=' . $item->object_id) );
    125 
    126         } elseif ( 'comment' == $item->slug ) {
    127 
    128             $name = sprintf( _x('Comment %s', 'Comment id', 'wp-blame'), $item->object_id );
    129             $link = esc_url( admin_url('comment.php?action=editcomment&c=' . $item->object_id) );
    130 
    131         } elseif ( 'user' == $item->slug ) {
    132 
    133             $name = sprintf( _x('User %s', 'User id', 'wp-blame'), $item->object_id );
    134             $link = esc_url( admin_url('user-edit.php?user_id=' . $item->object_id) );
    135 
    136         } elseif ( 'theme' == $item->slug ) {
    137 
    138             $name = __('Theme', 'wp-blame');
    139             $link = esc_url( admin_url('themes.php') );
    140 
    141         } elseif ( 'plugin' == $item->slug ) {
    142 
    143             $name = __('Plugin', 'wp-blame');
    144             $link = esc_url( admin_url('plugins.php') );
    145 
    146         } elseif ( 'option' == $item->slug ) {
    147 
    148             $name = __('Option', 'wp-blame');
    149             $link = esc_url( admin_url('options.php') );
    150 
    151         } else {
    152 
    153             return '<abbr title="' . __('Item could not be found.', 'wp-blame') . '">' . __('Not Found', 'wp-blame') . '</abbr>';
    154 
    155         }
    156 
    157         return '<a href="' . $link . '">' . $name . '</a>';
    158 
    159     }
    160 
    161     /**
    162      * Return the log action column.
    163      *
    164      * @since 2.0
    165      *
    166      * @param object $item Current row item.
    167      *
    168      * @return string
    169      */
    170     public function column_action( $item ) {
    171 
    172         return $item->action;
    173    
    174     }
    175 
    176     /**
    177      * Return the user column.
    178      *
    179      * @since 2.0
    180      *
    181      * @param object $item Current row item.
    182      *
    183      * @return string
    184      */
    185     public function column_user_id( $item ) {
    186        
    187         $get_user_data = get_userdata( $item->user_id );
    188 
    189         if ( ! empty( $get_user_data ) ) {
    190 
    191             $get_display_name = $get_user_data->display_name;
    192 
    193             if ( ! empty( $item->host_ip ) ) {
    194 
    195                 return '<a href="' . admin_url('user-edit.php?user_id=') . $item->user_id . '" class="profile" title="' . __('IP: ', 'wp-blame') . $item->host_ip . '">' . $get_display_name . '</a>';
    196 
    197             } else {
    198 
    199                 return '<a href="' . admin_url('user-edit.php?user_id=') . $item->user_id . '" class="profile">' . $get_display_name . '</a>';
    200 
    201             }
    202 
    203         } else {
    204 
    205             return '<abbr title="' . __('IP: ', 'wp-blame') . $item->host_ip . '">' . __('Unknown', 'wp-blame') . '</abbr>';
    206 
    207         }
    208    
    209     }
    210 
    211     /**
    212      * Return the notes column.
    213      *
    214      * @since 2.0
    215      *
    216      * @param object $item Current row item.
    217      *
    218      * @return string
    219      */
    220     public function column_notes( $item ) {
    221    
    222         return $item->notes;
    223    
    224     }
    225 
    226     /**
    227      * Return the time stamp column.
    228      *
    229      * @since 2.0
    230      *
    231      * @param object $item Current row item.
    232      *
    233      * @return string
    234      */
    235     public function column_timestamp( $item ) {
    236    
    237         return '<abbr title="' . date( _x('F jS Y H:i:s a', 'PHP date format', 'wp-blame'), strtotime( $item->timestamp ) ) . '">' . date( 'Y/m/d', strtotime( $item->timestamp ) ) . '</abbr>';
    238    
    239     }
    240 
    241     /**
    242      * Return the default (unknown) column.
    243      *
    244      * @since 2.0
    245      *
    246      * @param object $item Current row item.
    247      *
    248      * @return string
    249      */
    250     public function column_default( $item, $column_name ) {
    251 
    252         return $item->$column_name;
    253 
    254     }
    255 
    256     /**
    257      * Return the no logs found notice.
    258      *
    259      * @since 2.0
    260      *
    261      * @return string
    262      */
    263     public function no_items() {
    264    
    265         _e('There are no logs to show right now.', 'wp-blame');
    266    
    267     }
    268 
    269     /**
    270      * Define the bulk option items.
    271      *
    272      * @since 2.0
    273      *
    274      * @return array
    275      */
    276     public function get_bulk_actions() {
    277 
    278         return array(
    279             'delete' => __('Delete', 'wp-blame')
    280         );
    281 
    282     }
    283 
    284     /**
    285      * Get the total number of logs.
    286      *
    287      * @since 2.0
    288      *
    289      * @return string
    290      */
    291     public function get_total_logs() {
    292 
    293         global $wpdb;
    294 
    295         // Query to count the log rows
    296         $total_logs = $wpdb->get_var('SELECT COUNT(*) FROM ' . $wpdb->prefix . 'logs');
    297 
    298         return $total_logs;
    299 
    300     }
    301 
    302     /**
    303      * Process the bulk actions.
    304      *
    305      * @since 2.0
    306      *
    307      * @return void
    308      */
    309     public function process_bulk_action() {
    310 
    311         global $wpdb;
    312 
    313         if ( isset( $_POST['_wpnonce'] ) ) {
    314 
    315             $nonce  = sanitize_text_field( $_POST['_wpnonce'] );
    316             $action = $this->current_action();
    317 
    318             if ( wp_verify_nonce( $nonce, 'bulk-' . $this->_args['plural'] ) && isset( $_POST['log'] ) && 'delete' == $action ) {
    319 
    320                 foreach ( $_POST['log'] as $log ) {
    321 
    322                     $log = sanitize_text_field( $log );
    323 
    324                     $wpdb->query(
    325                         $wpdb->prepare(
    326                             'DELETE FROM ' . $wpdb->prefix . 'logs WHERE log_id = %s LIMIT 1',
    327                             $log
    328                         )
    329                     );
    330 
    331                 }
    332 
    333             }
    334 
    335         }
    336 
    337     }
    338 
    339     /**
    340      * Prepare the items for output.
    341      *
    342      * @since 2.0
    343      *
    344      * @return void
    345      */
    346     public function prepare_items() {
    347 
    348         global $wpdb;
    349 
    350         $screen = get_current_screen();
    351         $per_page = get_user_meta( get_current_user_id(), 'wpb_logs_per_page', true );
    352 
    353         if ( false === $per_page || $per_page < 1 ) {
    354 
    355             $per_page = $screen->get_option( 'wpb_logs_per_page', 20 );
    356 
    357         }
    358 
    359         $columns = $this->get_columns();
    360         $hidden = array();
    361         $sortable = $this->get_sortable_columns();
    362         $this->_column_headers = array( $columns, $hidden, $sortable );
    363         $this->process_bulk_action();
    364 
    365         $current_page = $this->get_pagenum();
    366         $total_items = $this->get_total_logs();
    367 
    368         $this->set_pagination_args([
    369             'total_items' => $total_items,
    370             'per_page'    => $per_page,
    371             'total_pages' => ceil( $total_items / $per_page )
    372         ]);
    373 
    374         if ( ( ! empty( $_REQUEST['orderby'] ) ) && ( ! empty( $_REQUEST['order'] ) ) ) {
    375 
    376             $query = 'SELECT * FROM ' . $wpdb->prefix . 'logs';
    377 
    378             $order_by = sanitize_text_field( strtoupper( $_REQUEST['orderby'] ) );
    379             $order_col = sanitize_text_field( strtoupper( $_REQUEST['order'] ) );
    380 
    381             $query .= ' ORDER BY ' . $order_by;
    382             $query .= $order_col == 'ASC' ? ' ' . $order_col : ' ' . $order_col;
    383 
    384         } else {
    385 
    386             $query = 'SELECT * FROM ' . $wpdb->prefix . 'logs ORDER BY log_id DESC';
    387 
    388         }
    389 
    390         if ( $current_page >= 1 ) {
    391 
    392             $query .= ' LIMIT ' . $per_page;
    393             $query .= ' OFFSET ' . ($current_page - 1) * $per_page;
    394 
    395         }
    396 
    397         $this->items = $wpdb->get_results($query);
    398 
    399     }
    400 
     8    /**
     9     * Initialise the logs table.
     10     *
     11     * @since 2.0
     12     *
     13     * @return void
     14     */
     15    public function __construct() {
     16        parent::__construct(
     17            array(
     18                'singular' => __('Log', 'wp-blame'),
     19                'plural' => __('Logs', 'wp-blame'),
     20                'ajax' => false
     21            )
     22        );
     23
     24        $this->prepare_items();
     25    }
     26
     27    /**
     28     * Define the table columns.
     29     *
     30     * @since 2.0
     31     *
     32     * @return array
     33     */
     34    public function get_columns() {
     35        $columns = [
     36            'cb'        => '<input type="checkbox" />',
     37            'log_id'    => __('Log', 'wp-blame'),
     38            'item'      => __('Item', 'wp-blame'),
     39            'action'    => __('Action', 'wp-blame'),
     40            'user_id'   => __('User', 'wp-blame'),
     41            'notes'     => __('Notes', 'wp-blame'),
     42            'timestamp' => __('Date', 'wp-blame')
     43        ];
     44
     45        return $columns;
     46    }
     47
     48    /**
     49     * Set which columns are sortable.
     50     *
     51     * @since 2.0
     52     *
     53     * @return array
     54     */
     55    public function get_sortable_columns() {
     56        $sortable_columns = array(
     57            'timestamp' => array('timestamp', false)
     58        );
     59
     60        return $sortable_columns;
     61    }
     62
     63    /**
     64     * Return the checkbox column.
     65     *
     66     * @since 2.0
     67     *
     68     * @param object $item Current row item.
     69     *
     70     * @return string
     71     */
     72    public function column_cb( $item ) {
     73        return sprintf('<input type="checkbox" name="%1$s[]" value="%2$s" />', $this->_args['singular'], $item->log_id );
     74    }
     75
     76    /**
     77     * Return the log id column.
     78     *
     79     * @since 2.0
     80     *
     81     * @param object $item Current row item.
     82     *
     83     * @return string
     84     */
     85    public function column_log_id( $item ) {
     86        return $item->log_id;
     87    }
     88
     89    /**
     90     * Return the log type column.
     91     *
     92     * @since 2.0
     93     *
     94     * @param object $item Current row item.
     95     *
     96     * @return string
     97     */
     98    public function column_item( $item ) {
     99        if ( 'post' == $item->slug ) {
     100            $name = ! empty( get_the_title( $item->object_id ) ) ? get_the_title( $item->object_id ) : __('Post', 'wp-blame');
     101            $link = esc_url( admin_url('post.php?post=' . $item->object_id . '&action=edit') );
     102        } elseif ( 'term' == $item->slug ) {
     103            $term = get_term( $item->object_id );
     104            $name = ! empty( $term->name ) ? $term->name : __('Term', 'wp-blame');
     105            $link = esc_url( admin_url('term.php?tag_ID=' . $item->object_id) );
     106        } elseif ( 'media' == $item->slug ) {
     107            $name = ! empty( get_the_title( $item->object_id ) ) ? get_the_title( $item->object_id ) : __('Media', 'wp-blame');
     108            $link = esc_url( admin_url('upload.php?item=' . $item->object_id) );
     109        } elseif ( 'comment' == $item->slug ) {
     110            $name = sprintf( _x('Comment %s', 'Comment id', 'wp-blame'), $item->object_id );
     111            $link = esc_url( admin_url('comment.php?action=editcomment&c=' . $item->object_id) );
     112        } elseif ( 'user' == $item->slug ) {
     113            $name = sprintf( _x('User %s', 'User id', 'wp-blame'), $item->object_id );
     114            $link = esc_url( admin_url('user-edit.php?user_id=' . $item->object_id) );
     115        } elseif ( 'theme' == $item->slug ) {
     116            $name = __('Theme', 'wp-blame');
     117            $link = esc_url( admin_url('themes.php') );
     118        } elseif ( 'plugin' == $item->slug ) {
     119            $name = __('Plugin', 'wp-blame');
     120            $link = esc_url( admin_url('plugins.php') );
     121        } elseif ( 'option' == $item->slug ) {
     122            $name = __('Option', 'wp-blame');
     123            $link = esc_url( admin_url('options.php') );
     124        } else {
     125            return '<abbr title="' . __('Item could not be found.', 'wp-blame') . '">' . __('Not Found', 'wp-blame') . '</abbr>';
     126        }
     127
     128        return '<a href="' . $link . '">' . $name . '</a>';
     129    }
     130
     131    /**
     132     * Return the log action column.
     133     *
     134     * @since 2.0
     135     *
     136     * @param object $item Current row item.
     137     *
     138     * @return string
     139     */
     140    public function column_action( $item ) {
     141        return $item->action;
     142    }
     143
     144    /**
     145     * Return the user column.
     146     *
     147     * @since 2.0
     148     *
     149     * @param object $item Current row item.
     150     *
     151     * @return string
     152     */
     153    public function column_user_id( $item ) {
     154        $get_user_data = get_userdata( $item->user_id );
     155
     156        if ( ! empty( $get_user_data ) ) {
     157            $get_display_name = $get_user_data->display_name;
     158
     159            if ( ! empty( $item->host_ip ) ) {
     160                return '<a href="' . admin_url('user-edit.php?user_id=') . $item->user_id . '" class="profile" title="' . __('IP: ', 'wp-blame') . $item->host_ip . '">' . $get_display_name . '</a>';
     161            } else {
     162                return '<a href="' . admin_url('user-edit.php?user_id=') . $item->user_id . '" class="profile">' . $get_display_name . '</a>';
     163            }
     164        } else {
     165            return '<abbr title="' . __('IP: ', 'wp-blame') . $item->host_ip . '">' . __('Unknown', 'wp-blame') . '</abbr>';
     166        }
     167    }
     168
     169    /**
     170     * Return the notes column.
     171     *
     172     * @since 2.0
     173     *
     174     * @param object $item Current row item.
     175     *
     176     * @return string
     177     */
     178    public function column_notes( $item ) {
     179        return $item->notes;
     180    }
     181
     182    /**
     183     * Return the time stamp column.
     184     *
     185     * @since 2.0
     186     *
     187     * @param object $item Current row item.
     188     *
     189     * @return string
     190     */
     191    public function column_timestamp( $item ) {
     192        return '<abbr title="' . date( _x('F jS Y H:i:s a', 'PHP date format', 'wp-blame'), strtotime( $item->timestamp ) ) . '">' . date( 'Y/m/d', strtotime( $item->timestamp ) ) . '</abbr>';
     193    }
     194
     195    /**
     196     * Return the default (unknown) column.
     197     *
     198     * @since 2.0
     199     *
     200     * @param object $item Current row item.
     201     * @param string $column_name Column name.
     202     *
     203     * @return string
     204     */
     205    public function column_default( $item, $column_name ) {
     206        return $item->$column_name;
     207    }
     208
     209    /**
     210     * Return the no logs found notice.
     211     *
     212     * @since 2.0
     213     *
     214     * @return void
     215     */
     216    public function no_items() {
     217        _e('There are no logs to show right now.', 'wp-blame');
     218    }
     219
     220    /**
     221     * Define the bulk option items.
     222     *
     223     * @since 2.0
     224     *
     225     * @return array
     226     */
     227    public function get_bulk_actions() {
     228        return array(
     229            'delete' => __('Delete', 'wp-blame')
     230        );
     231    }
     232
     233    /**
     234     * Get the total number of logs.
     235     *
     236     * @since 2.0
     237     *
     238     * @return int
     239     */
     240    public function get_total_logs() {
     241        global $wpdb;
     242
     243        // Query to count the log rows
     244        $total_logs = $wpdb->get_var('SELECT COUNT(*) FROM ' . $wpdb->prefix . 'logs');
     245
     246        return intval($total_logs);
     247    }
     248
     249    /**
     250     * Process the bulk actions.
     251     *
     252     * @since 2.0
     253     *
     254     * @return void
     255     */
     256    public function process_bulk_action() {
     257        global $wpdb;
     258
     259        if ( isset( $_POST['_wpnonce'] ) ) {
     260            $nonce  = sanitize_text_field( $_POST['_wpnonce'] );
     261            $action = $this->current_action();
     262
     263            if ( wp_verify_nonce( $nonce, 'bulk-' . $this->_args['plural'] ) && isset( $_POST['log'] ) && 'delete' == $action ) {
     264                foreach ( $_POST['log'] as $log ) {
     265                    $log = sanitize_text_field( $log );
     266
     267                    $wpdb->query(
     268                        $wpdb->prepare(
     269                            'DELETE FROM ' . $wpdb->prefix . 'logs WHERE log_id = %s LIMIT 1',
     270                            $log
     271                        )
     272                    );
     273                }
     274            }
     275        }
     276    }
     277
     278    /**
     279     * Prepare the items for output.
     280     *
     281     * @since 2.0
     282     *
     283     * @return void
     284     */
     285    public function prepare_items() {
     286        global $wpdb;
     287
     288        $screen = get_current_screen();
     289        $per_page = get_user_meta( get_current_user_id(), 'wpb_logs_per_page', true );
     290
     291        if ( false === $per_page || $per_page < 1 ) {
     292            $per_page = $screen->get_option( 'per_page', 'default' ) ?: 20;
     293        }
     294
     295        // Ensure $per_page is at least 1
     296        $per_page = max(1, intval($per_page));
     297
     298        $columns = $this->get_columns();
     299        $hidden = array();
     300        $sortable = $this->get_sortable_columns();
     301        $this->_column_headers = array( $columns, $hidden, $sortable );
     302        $this->process_bulk_action();
     303
     304        $current_page = $this->get_pagenum();
     305        $total_items = $this->get_total_logs();
     306
     307        $this->set_pagination_args([
     308            'total_items' => $total_items,
     309            'per_page'    => $per_page,
     310            'total_pages' => $total_items > 0 ? ceil( $total_items / $per_page ) : 1
     311        ]);
     312
     313        $order_by = ! empty( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : 'log_id';
     314        $order = ! empty( $_REQUEST['order'] ) ? sanitize_text_field( $_REQUEST['order'] ) : 'DESC';
     315
     316        $query = $wpdb->prepare(
     317            "SELECT * FROM {$wpdb->prefix}logs ORDER BY %s %s LIMIT %d OFFSET %d",
     318            $order_by,
     319            $order,
     320            $per_page,
     321            ($current_page - 1) * $per_page
     322        );
     323
     324        $this->items = $wpdb->get_results($query);
     325    }
    401326}
    402 
  • wp-blame/trunk/readme.txt

    r3060600 r3115598  
    44Donate link: https://wpcorner.co/donate
    55Requires at least: 4.0
    6 Tested up to: 6.5
     6Tested up to: 6.
    77Requires PHP: 5.4
    8 Stable tag: 2.1.5
     8Stable tag: 2.1.
    99License: GNU GPL v2
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    1616= About =
    1717
    18 WP Blame lets you keep a record of everything that has happened on your website by logging the actions of your users in a simple but useful table of data.
     18WP Blame lets you keep a record of everything that has happened on your website by logging the actions of your users in a simple but useful table of data.
     19
     20This plugin is your go-to solution for maintaining a complete audit trail of all user activities on your WordPress site. Whether you're a site administrator, developer, or security professional, WP Blame provides you with the insights you need to keep your site secure and well-managed.
     21
     22= Key Features =
     23
     24* **Comprehensive Logging:** Track all user actions including post edits, plugin activations, theme changes, and more.
     25* **User-Friendly Interface:** View all logged activities in an easy-to-read table right in your WordPress admin area.
     26* **Detailed Information:** Each log entry includes the user, action type, affected item, and date stamp.
     27* **User-Based Log Control:** Decide which usernames of people who should not have their actions logged.
     28
     29= Perfect For =
     30
     31* Troubleshooting unexpected changes
     32* Monitoring user activity for security purposes
     33* Maintaining compliance with audit requirements
     34* Tracking the history of your site's development and content changes
    1935
    2036= Developers =
     
    2238There are currently no hooks available for this plugin as of yet, however whilst it is discouraged, you can log actions using the `WPB_Log_Hooks::save_new_log` function.
    2339
     40
     41
     42
     43
     44
     45
     46
     47
     48
    2449== Screenshots ==
    2550
    26511. An example of the logs table.
     52
    2753
    2854== Installation ==
    2955
    30 1. Download, unzip and upload the package to your plugins directory.
    31 2. Log into the dashboard and activate within the plugins page.
    32 3. Review your website logs under Tools > Logs.
     561.
     572.
     583.
    3359
    3460== Frequently Asked Questions ==
     
    4672You can add usernames to a whitelist of people who's actions should not be logged on the website.
    4773
     74
     75
     76
     77
    4878== Changelog ==
     79
     80
     81
     82
     83
     84
    4985
    5086= 2.1.5 =
     
    85121== Upgrade Notice ==
    86122
    87 = 2.1.4 =
     123= 2.1. =
    88124
    89 * Minor fix
     125*
  • wp-blame/trunk/wp-blame.php

    r3060600 r3115598  
    88 * Author URI: https://wpcorner.co/author/patrick-l/
    99 * Text Domain: wp-blame
    10  * Version: 2.1.5
     10 * Version: 2.1.
    1111 */
    1212
     
    331331
    332332}
    333 
Note: See TracChangeset for help on using the changeset viewer.