register_plugin ('audit-trail', dirname (__FILE__)); $this->add_filter ('audit_collect'); $this->add_action ('audit_listen'); $this->add_filter ('audit_show_operation'); $this->add_filter ('audit_show_item'); $this->add_filter ('audit_show_details'); } /** * Register the types of data we can collect * * @return array Types to listen for **/ function audit_collect ($items) { $items['post'] = __ ('Post & page management', 'audit-trail'); $items['attach'] = __ ('File attachments', 'audit-trail'); $items['user'] = __ ('User profiles & logins', 'audit-trail'); $items['theme'] = __ ('Theme switching', 'audit-trail'); $items['link'] = __ ('Link management', 'audit-trail'); $items['category'] = __ ('Category management', 'audit-trail'); $items['comment'] = __ ('Comment management', 'audit-trail'); $items['viewing'] = __ ('User page visits', 'audit-trail'); $items['audit'] = __ ('Audit Trail actions', 'audit-trail'); return $items; } /** * Insert the hooks to listen for, given a particular area, into the list of actions * * @param string $method The type of area we are listening in * @return void **/ function audit_listen ($method) { $ignore = get_option ('audit_ignore'); if ($ignore) { $current = wp_get_current_user (); $users = explode (',', $ignore); if (in_array ($current->ID, $users)) return; } $actions = array (); if ($method == 'post') $actions = array ('delete_post', 'save_post', 'private_to_published'); else if ($method == 'attach') $actions = array ('delete_attachment', 'add_attachment', 'edit_attachment'); else if ($method == 'user') $actions = array ('wp_login', 'wp_logout', 'user_register', 'profile_update', 'delete_user', 'retrieve_password', 'login_errors'); else if ($method == 'theme') $actions = array ('switch_theme'); else if ($method == 'link') $actions = array ('edit_link', 'add_link', 'delete_link'); else if ($method == 'category') $actions = array ('edit_category', 'add_category', 'delete_category'); else if ($method == 'comment') $actions = array ('edit_comment', 'delete_comment'); else if ($method == 'viewing') $actions = array ('template_redirect'); foreach ($actions AS $name) $this->add_action ($name); } /** * Given a log item will display the details * * @param AT_Audit $item * @return AT_Audit **/ function audit_show_details ($item) { global $wpdb; switch ($item->operation) { case 'user_register' : case 'profile_update' : $user = unserialize ($item->data); $item->message = '
'.$this->capture_admin ('details/profile_update', array ('item' => $item, 'user' => $user)); break; case 'add_link' : case 'edit_link' : $link = unserialize ($item->data); $item->message = '
'.$this->capture_admin ('details/edit_link', array ('item' => $item, 'link' => $link)); break; case 'add_category' : case 'edit_category' : $cat = unserialize ($item->data); $item->message = '
'.$this->capture_admin ('details/edit_category', array ('item' => $item, 'cat' => $cat)); break; case 'edit_comment' : $original = get_comment ($item->item_id); $comment = unserialize ($item->data); $item->message = '
'.$this->capture_admin ('details/'.$item->operation, array ('item' => $item, 'comment' => $comment)); break; case 'save_post' : $original = get_post ($item->item_id); $post = unserialize ($item->data); $item->message = '
'.$this->capture_admin ('details/'.$item->operation, array ('item' => $item, 'post' => $post)); break; } return $item; } /** * Given a log item will pretty-print the item * * @param AT_Audit $item * @return AT_Audit **/ function audit_show_item ($item) { switch ($item->operation) { case 'delete_link' : case 'switch_theme' : $item->message = $item->data; break; case 'profile_update' : case 'wp_logout': case 'login_failed' : case 'wp_login' : $user = get_userdata ($item->item_id); if ($user === false) $item->message = $item->item_id; else $item->message = ''.$user->user_nicename.""; break; case 'user_register' : $user = unserialize ($item->data); $item->message = ''.$user->user_nicename.""; break; case 'delete_user' : case 'retrieve_password' : $user = get_userdatabylogin ($item->data); if ($user === false) $item->message = $item->data; else $item->message = ''.$user->user_nicename.""; break; case 'add_link' : case 'edit_link' : $link = unserialize ($item->data); $item->message = ''.$link->link_name.''; break; case 'edit_category' : case 'add_category' : $cat = unserialize ($item->data); $item->message = ''.$cat->cat_name.''; break; case 'edit_comment' : $item->message = ''.$item->item_id.''; break; case 'save_post' : $post = unserialize ($item->data); if ( $post ) $item->message = ''.$post->post_title.''; break; case 'private_to_published': $post = get_post ($item->item_id); if ( $post ) $item->message = ''.$post->post_title.''; break; case 'add_attachment' : case 'edit_attachment' : $post = get_post ($item->item_id); $text = ''.basename ($item->data).''; if (!empty ($post) && $post->post_parent > 0) $text .= ' (post '.$post->post_parent.')'; $item->message = $text; break; case 'template_redirect': if ($item->item_id > 0) $item->message = ''.$item->data.''; else $item->message = $item->data; break; } return $item; } /** * Given a log item will pretty-print the operation * * @param AT_Audit $item * @return AT_Audit **/ function audit_show_operation ($item) { switch ($item->operation) { case 'switch_theme' : $item->message = __ ('Theme switch', 'audit-trail'); break; case 'profile_update' : $user = get_userdata ($item->item_id); if ($user === false) $text = __ ('Profile updated for deleted user', 'audit-trail'); else $text = __ ('Profile updated', 'audit-trail'); $item->message = ''.$text.''; break; case 'wp_login' : $item->message = __ ('Logged In', 'audit-trail'); break; case 'wp_logout' : $item->message = __ ('Logged Out', 'audit-trail'); break; case 'login_failed' : $item->message = __ ('Login failed', 'audit-trail'); break; case 'user_register' : $item->message = ''.__ ('New user registration', 'audit-trail').''; break; case 'retrieve_password' : $item->message = __ ('Retrieve password', 'audit-trail'); break; case 'delete_user' : $item->message = __ ('Delete user', 'audit-trail'); break; case 'add_link' : $item->message = ''.__ ('Add link', 'audit-trail').''; break; case 'edit_link': $link = unserialize ($item->data); $item->message = ''.__ ('Edit link', 'audit-trail').''; break; case 'delete_link': $item->message = __ ('Delete link', 'audit-trail'); break; case 'edit_category' : $item->message = ''.__ ('Edit category ', 'audit-trail').''; break; case 'add_category': $item->message = ''.__ ('Add category', 'audit-trail').''; break; case 'delete_category' : $item->message = __ ('Delete category', 'audit-trail'); break; case 'edit_comment' : $item->message = ''.__ ('Edit comment', 'audit-trail').''; break; case 'delete_comment': $item->message = __ ('Delete comment', 'audit-trail'); break; case 'delete_post' : $item->message = __ ('Delete post', 'audit-trail'); break; case 'save_post' : $post = unserialize ($item->data); if ($post && $post->post_type == 'post') $text = __ ('Save post', 'audit-trail'); else $text = __ ('Save page', 'audit-trail'); $item->message = ''.$text.'';; break; case 'private_to_published' : $item->message = 'Published'; break; case 'add_attachment' : $item->message = ''.__ ('Add attachment', 'audit-trail').''; break; case 'delete_attachment' : $item->message = 'Delete attachment'; break; case 'edit_attachment' : $item->message = ''.__ ('Edit attachment', 'audit-trail').''; break; case 'template_redirect' : $item->message = __( 'View page', 'audit-trail' ); break; } return $item; } /** * Default listening methods **/ // Actions to track function delete_post ($id) { AT_Audit::create ('delete_post', $id); } function private_to_published ($id) { AT_Audit::create ('private_to_published', $id); } function save_post ($id) { if (!defined ('DOING_AJAX')) AT_Audit::create ('save_post', $id, get_post( $id ) ); } function wp_login ($user) { $data = get_user_by( 'login', $user ); AT_Audit::create ('wp_login', $data->ID, '', '', $data->ID); } function wp_logout () { global $user_ID; AT_Audit::create ('wp_logout', $user_ID); } function login_errors ($errors) { if (strpos ($errors, __('ERROR: Incorrect password.')) !== false) { $login = get_user_by( 'login', sanitize_user ($_POST['log'])); AT_Audit::create ('login_failed', $login->ID, sanitize_user ($_POST['log'])); } return $errors; } function switch_theme ($newtheme) { AT_Audit::create ('switch_theme', '', $newtheme); } function edit_link ($id) { global $wpdb; $link = $wpdb->get_row ("SELECT * FROM {$wpdb->links} WHERE link_id=$id"); AT_Audit::create ('edit_link', $id, serialize ($link)); } function delete_link ($id) { global $wpdb; $link = $wpdb->get_row ("SELECT * FROM {$wpdb->links} WHERE link_id=$id"); AT_Audit::create ('delete_link', $id, $link->link_name); } function add_link ($id) { global $wpdb; $link = $wpdb->get_row ("SELECT * FROM {$wpdb->links} WHERE link_id=$id"); AT_Audit::create ('add_link', $id, serialize ($link)); } function edit_category ($id) { // We filter here otherwise we get a lot of annoying messages whenever the admin does anything useful if (strpos ($_SERVER['REQUEST_URI'], 'categories.php') !== false) AT_Audit::create ('edit_category', $id, serialize (get_category ($id))); } function create_category ($id) { AT_Audit::create ('create_category', $id, serialize (get_category ($id))); } function add_category ($id) { AT_Audit::create ('add_category', $id, serialize (get_category ($id))); } function delete_category ($id) { $cat = get_category ($id); AT_Audit::create ('delete_category', $id, $cat->cat_nicename); } function user_register ($id) { AT_Audit::create ('user_register', $id, serialize (get_userdata ($id))); } function profile_update ($id) { AT_Audit::create ('profile_update', $id, serialize (get_userdata ($id))); } function delete_user ($id) { $user = get_userdata ($id); AT_Audit::create ('delete_user', $id, $user->user_nicename); } function retrieve_password ($name) { AT_Audit::create ('retrieve_password', '', $name); } function delete_comment ($id) { AT_Audit::create ('delete_comment', $id); } function edit_comment ($id) { global $wpdb; $comment = $wpdb->get_row ("SELECT * FROM {$wpdb->comments} WHERE comment_ID=$id"); AT_Audit::create ('edit_comment', $id, serialize ($comment)); } function delete_attachment ($postid) { AT_Audit::create ('delete_attachment', $postid); } function add_attachment ($postid) { global $wpdb; $attach = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->postmeta} WHERE post_id=%d AND meta_key='_wp_attached_file' ORDER BY meta_id DESC LIMIT 1", $postid ) ); AT_Audit::create ('add_attachment', $postid, $attach->meta_value); } function edit_attachment ($postid) { global $wpdb; $attach = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->postmeta} WHERE post_id=%d AND meta_key='_wp_attached_file' ORDER BY meta_id DESC LIMIT 1", $postid ) ); AT_Audit::create ('edit_attachment', $postid, $attach->meta_value); } function template_redirect () { // Don't log 404's if (!is_404 ()) { global $post, $posts; if (isset ($_GET['preview']) && $_GET['preview'] == 'true') return; AT_Audit::create ('template_redirect', count ($posts) > 1 ? 0 : $post->ID, $_SERVER['REQUEST_URI']); } } } ?>