diff --git a/connectors/media.php b/connectors/media.php index fb10ddd0f..f5b45c237 100644 --- a/connectors/media.php +++ b/connectors/media.php @@ -48,14 +48,49 @@ public static function get_action_labels() { /** * Return translated context labels * + * Based on extension types used by wp_ext2type() in wp-includes/functions.php. + * * @return array Context label translations */ public static function get_context_labels() { return array( - 'media' => __( 'Media', 'stream' ), + 'image' => __( 'Image', 'stream' ), + 'audio' => __( 'Audio', 'stream' ), + 'video' => __( 'Video', 'stream' ), + 'document' => __( 'Document', 'stream' ), + 'spreadsheet' => __( 'Spreadsheet', 'stream' ), + 'interactive' => __( 'Interactive', 'stream' ), + 'text' => __( 'Text', 'stream' ), + 'archive' => __( 'Archive', 'stream' ), + 'code' => __( 'Code', 'stream' ), ); } + /** + * Return the file type for an attachment which corresponds with a context label + * + * @param object $file_uri URI of the attachment + * @return string A file type which corresponds with a context label + */ + public static function get_attachment_type( $file_uri ) { + + $extension = pathinfo( $file_uri, PATHINFO_EXTENSION ); + $extension_type = wp_ext2type( $extension ); + + if ( empty( $extension_type ) ) { + $extension_type = 'document'; + } + + $context_labels = self::get_context_labels(); + + if ( ! isset( $context_labels[ $extension_type ] ) ) { + $extension_type = 'document'; + } + + return $extension_type; + + } + /** * Add action links to Stream drop row in admin list screen * @@ -92,16 +127,18 @@ public static function callback_add_attachment( $post_id ) { } else { $message = __( 'Added "%s" to Media library', 'stream' ); } - $name = $post->post_title; - $url = $post->guid; - $parent_id = $post->post_parent; - if ( $parent_id && $parent = get_post( $post->post_parent ) ) $parent_title = $parent->post_title; + $name = $post->post_title; + $url = $post->guid; + $parent_id = $post->post_parent; + $parent_title = $parent_id ? get_the_titleā€Ž( $parent_id ) : null; + + $attachment_type = self::get_attachment_type( $post->guid ); self::log( $message, compact( 'name', 'parent_title', 'parent_id', 'url' ), $post_id, - array( 'media' => $post->post_parent ? 'attached' : 'uploaded' ) + array( $attachment_type => $post->post_parent ? 'attached' : 'uploaded' ) ); } @@ -115,11 +152,13 @@ public static function callback_edit_attachment( $post_id ) { $message = __( 'Updated "%s"', 'stream' ); $name = $post->post_title; + $attachment_type = self::get_attachment_type( $post->guid ); + self::log( $message, compact( 'name' ), $post_id, - array( 'media' => 'updated' ) + array( $attachment_type => 'updated' ) ); } @@ -136,21 +175,26 @@ public static function callback_delete_attachment( $post_id ) { $name = $post->post_title; $url = $post->guid; + $attachment_type = self::get_attachment_type( $post->guid ); + self::log( $message, compact( 'name', 'parent_id', 'url' ), $post_id, - array( 'media' => 'deleted' ) + array( $attachment_type => 'deleted' ) ); } public static function callback_wp_save_image_editor_file( $dummy, $filename, $image, $mime_type, $post_id ) { $name = basename( $filename ); + + $attachment_type = self::get_attachment_type( $post->guid ); + self::log( __( 'Edited image "%s"', 'stream' ), compact( 'name', 'filename', 'post_id' ), $post_id, - array( 'media' => 'edited' ) + array( $attachment_type => 'edited' ) ); } diff --git a/includes/admin.php b/includes/admin.php index 4b5482a74..952276fbc 100644 --- a/includes/admin.php +++ b/includes/admin.php @@ -57,6 +57,9 @@ public static function load() { // Load Dashboard widget add_action( 'wp_dashboard_setup', array( __CLASS__, 'dashboard_stream_activity' ) ); + // Dashboard AJAX pagination + add_action( 'wp_ajax_stream_activity_dashboard_update', array( __CLASS__, 'dashboard_stream_activity_update_contents' ) ); + // Heartbeat live update add_filter( 'heartbeat_received', array( __CLASS__, 'live_update' ), 10, 2 ); @@ -143,6 +146,11 @@ public static function admin_enqueue_scripts( $hook ) { wp_enqueue_style( 'wp-stream-admin', WP_STREAM_URL . 'ui/admin.css', array() ); + if ( ! in_array( $hook, self::$screen_id ) && 'dashboard.php' !== $hook ) { + wp_enqueue_script( 'wp-stream-admin-dashboard', WP_STREAM_URL . 'ui/dashboard.js', array( 'jquery' ) ); + return; + } + if ( ! in_array( $hook, self::$screen_id ) && 'plugins.php' !== $hook ) { return; } @@ -503,20 +511,38 @@ public static function dashboard_stream_activity() { wp_add_dashboard_widget( 'dashboard_stream_activity', - __( 'Stream Activity', 'stream' ), - array( __CLASS__, 'dashboard_stream_activity_contents' ), + esc_html__( 'Stream Activity', 'stream' ), + array( __CLASS__, 'dashboard_stream_activity_initial_contents' ), array( __CLASS__, 'dashboard_stream_activity_options' ) ); } + public static function dashboard_get_total_found_rows(){ + global $wpdb; + return $wpdb->get_var( 'SELECT FOUND_ROWS()' ); + } + + public static function dashboard_stream_activity_initial_contents(){ + self::dashboard_stream_activity_contents(); + } + + public static function dashboard_stream_activity_update_contents(){ + + $paged = ! empty( $_POST['stream-paged'] ) ? absint( $_POST['stream-paged'] ) : 1; + self::dashboard_stream_activity_contents( $paged ); + die; + } + /** * Contents of the Stream Activity dashboard widget */ - public static function dashboard_stream_activity_contents() { - $options = get_option( 'dashboard_stream_activity_options', array() ); + public static function dashboard_stream_activity_contents( $paged = 1 ) { - $args = array( - 'records_per_page' => isset( $options['records_per_page'] ) ? absint( $options['records_per_page'] ) : 5, + $options = get_option( 'dashboard_stream_activity_options', array() ); + $records_per_page = isset( $options['records_per_page'] ) ? absint( $options['records_per_page'] ) : 5; + $args = array( + 'records_per_page' => $records_per_page, + 'paged' => $paged, ); $records = stream_query( $args ); @@ -581,12 +607,99 @@ public static function dashboard_stream_activity_contents() { echo ''; - echo sprintf( - '', + $total_items = self::dashboard_get_total_found_rows(); + $args = array( + 'total_pages' => ceil( $total_items / $records_per_page ), + 'current' => $paged, + ); + + self::dashboard_pagination( $args ); + } + + /* + * Display pagination links for Dashboard Widget + * Copied from private class WP_List_Table::pagination() + */ + public static function dashboard_pagination( $args = array() ){ + + $args = wp_parse_args( + $args, + array( + 'current' => 1, + 'total_pages' => 1, + ) + ); + extract( $args ); + + $records_link = add_query_arg( + array( 'page' => self::RECORDS_PAGE_SLUG ), + admin_url( self::ADMIN_PARENT_PAGE ) + ); + + $html_view_all = sprintf( + '%s', + 'view-all', + esc_attr__( 'View all records', 'stream' ), esc_url( $records_link ), - esc_attr__( 'View all Stream Records', 'stream' ), - esc_html__( 'More', 'stream' ) - ); // xss ok + esc_html__( 'View All', 'stream' ) + ); + + $page_links = array(); + $disable_first = $disable_last = ''; + if ( 1 === $current ){ + $disable_first = ' disabled'; + } + if ( $current === $total_pages ){ + $disable_last = ' disabled'; + } + + $page_links[] = sprintf( + '%s', + 'first-page' . $disable_first, + esc_attr__( 'Go to the first page', 'stream' ), + esc_url( remove_query_arg( 'paged', $records_link ) ), + '«' + ); + + $page_links[] = sprintf( + '%s', + 'prev-page' . $disable_first, + esc_attr__( 'Go to the previous page', 'stream' ), + esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $records_link ) ), + max( 1, $current - 1 ), + '‹' + ); + + $html_total_pages = sprintf( '%s', number_format_i18n( $total_pages ) ); + $page_links[] = '' . sprintf( _x( '%1$s of %2$s', 'paging', 'stream' ), $current, $html_total_pages ) . ''; + + $page_links[] = sprintf( + '%s', + 'next-page' . $disable_last, + esc_attr__( 'Go to the next page', 'stream' ), + esc_url( add_query_arg( 'paged', min( $total_pages, $current + 1 ), $records_link ) ), + min( $total_pages, $current + 1 ), + '›' + ); + + $page_links[] = sprintf( + '%s', + 'last-page' . $disable_last, + esc_attr__( 'Go to the last page', 'stream' ), + esc_url( add_query_arg( 'paged', $total_pages, $records_link ) ), + $total_pages, + '»' + ); + + $html_pagination_links = ' +
+
+ ' . join( "\n", $page_links ) . ' +
+
+
'; + + echo '
' . $html_view_all . $html_pagination_links . '
'; } /** @@ -595,7 +708,7 @@ public static function dashboard_stream_activity_contents() { public static function dashboard_stream_activity_options() { $options = get_option( 'dashboard_stream_activity_options', array() ); - if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset( $_POST['dashboard_stream_activity_options'] ) ) { + if ( 'POST' === $_SERVER['REQUEST_METHOD'] && isset( $_POST['dashboard_stream_activity_options'] ) ) { $options['records_per_page'] = absint( $_POST['dashboard_stream_activity_options']['records_per_page'] ); update_option( 'dashboard_stream_activity_options', $options ); } @@ -607,8 +720,8 @@ public static function dashboard_stream_activity_options() { ?>

- - + +

self::RECORDS_PAGE_SLUG ) ); diff --git a/includes/feeds.php b/includes/feeds.php index e4edc39ec..b605f873e 100644 --- a/includes/feeds.php +++ b/includes/feeds.php @@ -70,11 +70,11 @@ public static function user_feed_key( $user ) { ?> - +

- - + +

diff --git a/includes/install.php b/includes/install.php index f504dcea9..b8b587f38 100644 --- a/includes/install.php +++ b/includes/install.php @@ -165,6 +165,47 @@ public static function update( $db_version, $current ) { } } } + + // If version is lower than 1.2.8, do the update routine + // Change the context for Media connectors to the attachment type + if ( version_compare( $db_version, '1.2.8', '<' ) ) { + + require_once( WP_STREAM_CLASS_DIR . 'connector.php' ); + require_once( WP_STREAM_DIR . 'connectors/media.php' ); + + $sql = "SELECT r.ID id, r.object_id pid, c.meta_id mid + FROM $wpdb->stream r + JOIN $wpdb->streamcontext c + ON r.ID = c.record_id AND c.connector = 'media' AND c.context = 'media' + "; + $media_records = $wpdb->get_results( $sql ); // db call okay + + foreach ( $media_records as $record ) { + + $post = get_post( $record->pid ); + + if ( empty( $post ) ) { + $sql = "SELECT meta_value + FROM $wpdb->streammeta + WHERE meta_key = 'url' AND meta_id = %d + "; + $url = $wpdb->get_var( $wpdb->prepare( $sql, $record->mid ) ); + } else { + $url = $post->guid; + } + + if ( ! empty( $url ) ) { + $context = WP_Stream_Connector_Media::get_attachment_type( $url ); + $wpdb->update( + $wpdb->streamcontext, + array( 'context' => $context ), + array( 'record_id' => $record->id ), + array( '%s' ), + array( '%d' ) + ); + } + } + } } } diff --git a/includes/list-table.php b/includes/list-table.php index 607b6dce5..0a35a9e20 100644 --- a/includes/list-table.php +++ b/includes/list-table.php @@ -534,9 +534,9 @@ function filter_date() { ', - esc_attr__( 'Date start', 'stream' ), + esc_attr__( 'Start date', 'stream' ), isset( $_GET['date_from'] ) ? esc_attr( $_GET['date_from'] ) : null, - esc_attr__( 'Date end', 'stream' ), + esc_attr__( 'End date', 'stream' ), isset( $_GET['date_to'] ) ? esc_attr( $_GET['date_to'] ) : null ); diff --git a/includes/settings.php b/includes/settings.php index 52e2a5ae7..457cc570a 100644 --- a/includes/settings.php +++ b/includes/settings.php @@ -97,7 +97,7 @@ public static function get_fields() { __( 'Users from the selected roles above will be given a private key found in their %suser profile%s to access feeds of Stream Records securely.', 'stream' ), sprintf( '', - admin_url( 'profile.php' ), + admin_url( sprintf( 'profile.php#wp-stream-highlight:%s', WP_Stream_Feeds::USER_FEED_KEY ) ), esc_attr__( 'View Profile', 'stream' ) ), '' diff --git a/readme.md b/readme.md index 81c47ec9d..14d97d658 100755 --- a/readme.md +++ b/readme.md @@ -105,6 +105,9 @@ Thank you for wanting to make Stream better for everyone! We salute you. ## Changelog ## +### 1.2.7 ### +**2014/03/04** - Pagination added to Stream Activity dashboard widget. Bug fixes. Props [chacha](https://github.com/chacha/), [fjarrett](http://profiles.wordpress.org/fjarrett/) + ### 1.2.6 ### **2014/02/28** - Improved context names in Users connector. Props [powelski](http://profiles.wordpress.org/powelski/) diff --git a/readme.txt b/readme.txt index c51873dcf..0f1cf4ab0 100644 --- a/readme.txt +++ b/readme.txt @@ -90,6 +90,9 @@ Thank you for wanting to make Stream better for everyone! We salute you. == Changelog == += 1.2.7 = +**2014/03/04** - Pagination added to Stream Activity dashboard widget. Bug fixes. Props [chacha](https://github.com/chacha/), [fjarrett](http://profiles.wordpress.org/fjarrett/) + = 1.2.6 = **2014/02/28** - Improved context names in Users connector. Props [powelski](http://profiles.wordpress.org/powelski/) diff --git a/stream.php b/stream.php index 09a080722..2f0db204a 100644 --- a/stream.php +++ b/stream.php @@ -3,7 +3,7 @@ * Plugin Name: Stream * Plugin URI: http://wordpress.org/plugins/stream/ * Description: Stream tracks logged-in user activity so you can monitor every change made on your WordPress site in beautifully organized detail. All activity is organized by context, action and IP address for easy filtering. Developers can extend Stream with custom connectors to log any kind of action. - * Version: 1.2.6 + * Version: 1.2.7 * Author: X-Team * Author URI: http://x-team.com/wordpress/ * License: GPLv2+ @@ -37,7 +37,7 @@ class WP_Stream { * * @const string */ - const VERSION = '1.2.6'; + const VERSION = '1.2.7'; /** * Hold Stream instance diff --git a/ui/admin.css b/ui/admin.css index b1a93ab69..c16373fee 100644 --- a/ui/admin.css +++ b/ui/admin.css @@ -2,6 +2,10 @@ border-bottom: 0; } +#dashboard_stream_activity h3 .postbox-title-action { + top: 6px; +} + #dashboard_stream_activity.postbox .inside, #dashboard_stream_activity ul, #dashboard_stream_activity ul li { @@ -14,6 +18,10 @@ padding: 1em 12px; } +#dashboard_stream_activity ul { + border-bottom: 1px solid #eee; +} + #dashboard_stream_activity ul li, #dashboard_stream_activity .sub-links { padding: 1em 12px; @@ -45,6 +53,20 @@ padding: 12px; } +#dashboard_stream_activity .tablenav { + clear: none; + margin: 4px 0 6px; +} + +#dashboard_stream_activity .tablenav .tablenav-pages { + margin-right: 6px; +} + +#dashboard_stream_activity .view-all { + float: left; + margin: 7px 0 0 12px; +} + .toplevel_page_wp_stream .tablenav { padding-top: 6px; } @@ -101,6 +123,18 @@ } } +@media only screen and (max-width: 782px) { + #dashboard_stream_activity h3 .postbox-title-action { + top: 10px; + } + #dashboard_stream_activity .view-all { + display: none; + } + #dashboard_stream_activity .tablenav .tablenav-pages { + margin: 15px 0; + } +} + @media only screen and (max-width: 480px) { .toplevel_page_wp_stream .fixed .column-author { display: none; @@ -127,6 +161,7 @@ .toplevel_page_wp_stream .alignleft.actions input[type=text] { height: 27px; + line-height: 19px; } .toplevel_page_wp_stream .select2-container { @@ -165,3 +200,7 @@ .toplevel_page_wp_stream .new-row.fadeout { background-color: transparent; } + +.stream_page_wp_stream_settings .nav-tab-wrapper a:not(.nav-tab-active) { + border-bottom: 1px solid #ccc; +} diff --git a/ui/admin.js b/ui/admin.js index 553d3a0f3..f27d0983e 100644 --- a/ui/admin.js +++ b/ui/admin.js @@ -84,13 +84,13 @@ jQuery(function($){ $optionsForm.prop('action', currentAction.replace( /(^[^#]*).*$/, '$1#' + index )); }; - $tabs.on('click', 'a', function(e){ - e.preventDefault(); + $tabs.on('click', 'a', function(){ var index = $tabs.find('a').index( $(this) ); $panels.hide().eq(index).show(); $tabs.find('a').removeClass('nav-tab-active').filter($(this)).addClass('nav-tab-active'); window.location.hash = index; syncFormAction(index); + return false; }); $tabs.children().eq( currentHash ).trigger('click'); diff --git a/ui/dashboard.js b/ui/dashboard.js new file mode 100644 index 000000000..3b532abe2 --- /dev/null +++ b/ui/dashboard.js @@ -0,0 +1,16 @@ +/* dashboard pagination */ +jQuery(function($){ + + $( '#dashboard_stream_activity').on( 'click', '.pagination-links a', function(e){ + e.preventDefault(); + var data = { + 'action' : 'stream_activity_dashboard_update', + 'stream-paged' : $(this).data('page'), + }; + + $.post( window.ajaxurl, data, function( response ){ + $( '#dashboard_stream_activity .inside' ).html( response ); + } ); + } ); + +});