WordPress 3.4
[autoinstalls/wordpress.git] / wp-admin / includes / dashboard.php
1 <?php
2 /**
3  * WordPress Dashboard Widget Administration Screen API
4  *
5  * @package WordPress
6  * @subpackage Administration
7  */
8
9 /**
10  * Registers dashboard widgets.
11  *
12  * Handles POST data, sets up filters.
13  *
14  * @since 2.5.0
15  */
16 function wp_dashboard_setup() {
17         global $wp_registered_widgets, $wp_registered_widget_controls, $wp_dashboard_control_callbacks;
18         $wp_dashboard_control_callbacks = array();
19         $screen = get_current_screen();
20
21         $update = false;
22         $widget_options = get_option( 'dashboard_widget_options' );
23         if ( !$widget_options || !is_array($widget_options) )
24                 $widget_options = array();
25
26         /* Register Widgets and Controls */
27
28         $response = wp_check_browser_version();
29
30         if ( $response && $response['upgrade'] ) {
31                 add_filter( 'postbox_classes_dashboard_dashboard_browser_nag', 'dashboard_browser_nag_class' );
32                 if ( $response['insecure'] )
33                         wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'You are using an insecure browser!' ), 'wp_dashboard_browser_nag' );
34                 else
35                         wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'Your browser is out of date!' ), 'wp_dashboard_browser_nag' );
36         }
37
38         // Right Now
39         if ( is_blog_admin() && current_user_can('edit_posts') )
40                 wp_add_dashboard_widget( 'dashboard_right_now', __( 'Right Now' ), 'wp_dashboard_right_now' );
41
42         if ( is_network_admin() )
43                 wp_add_dashboard_widget( 'network_dashboard_right_now', __( 'Right Now' ), 'wp_network_dashboard_right_now' );
44
45         // Recent Comments Widget
46         if ( is_blog_admin() && current_user_can('moderate_comments') ) {
47                 if ( !isset( $widget_options['dashboard_recent_comments'] ) || !isset( $widget_options['dashboard_recent_comments']['items'] ) ) {
48                         $update = true;
49                         $widget_options['dashboard_recent_comments'] = array(
50                                 'items' => 5,
51                         );
52                 }
53                 $recent_comments_title = __( 'Recent Comments' );
54                 wp_add_dashboard_widget( 'dashboard_recent_comments', $recent_comments_title, 'wp_dashboard_recent_comments', 'wp_dashboard_recent_comments_control' );
55         }
56
57         // Incoming Links Widget
58         if ( is_blog_admin() && current_user_can('publish_posts') ) {
59                 if ( !isset( $widget_options['dashboard_incoming_links'] ) || !isset( $widget_options['dashboard_incoming_links']['home'] ) || $widget_options['dashboard_incoming_links']['home'] != get_option('home') ) {
60                         $update = true;
61                         $num_items = isset($widget_options['dashboard_incoming_links']['items']) ? $widget_options['dashboard_incoming_links']['items'] : 10;
62                         $widget_options['dashboard_incoming_links'] = array(
63                                 'home' => get_option('home'),
64                                 'link' => apply_filters( 'dashboard_incoming_links_link', 'http://blogsearch.google.com/blogsearch?scoring=d&partner=wordpress&q=link:' . trailingslashit( get_option('home') ) ),
65                                 'url' => isset($widget_options['dashboard_incoming_links']['url']) ? apply_filters( 'dashboard_incoming_links_feed', $widget_options['dashboard_incoming_links']['url'] ) : apply_filters( 'dashboard_incoming_links_feed', 'http://blogsearch.google.com/blogsearch_feeds?scoring=d&ie=utf-8&num=' . $num_items . '&output=rss&partner=wordpress&q=link:' . trailingslashit( get_option('home') ) ),
66                                 'items' => $num_items,
67                                 'show_date' => isset($widget_options['dashboard_incoming_links']['show_date']) ? $widget_options['dashboard_incoming_links']['show_date'] : false
68                         );
69                 }
70                 wp_add_dashboard_widget( 'dashboard_incoming_links', __( 'Incoming Links' ), 'wp_dashboard_incoming_links', 'wp_dashboard_incoming_links_control' );
71         }
72
73         // WP Plugins Widget
74         if ( ( ! is_multisite() && is_blog_admin() && current_user_can( 'install_plugins' ) ) || ( is_network_admin() && current_user_can( 'manage_network_plugins' ) && current_user_can( 'install_plugins' ) ) )
75                 wp_add_dashboard_widget( 'dashboard_plugins', __( 'Plugins' ), 'wp_dashboard_plugins' );
76
77         // QuickPress Widget
78         if ( is_blog_admin() && current_user_can('edit_posts') )
79                 wp_add_dashboard_widget( 'dashboard_quick_press', __( 'QuickPress' ), 'wp_dashboard_quick_press' );
80
81         // Recent Drafts
82         if ( is_blog_admin() && current_user_can('edit_posts') )
83                 wp_add_dashboard_widget( 'dashboard_recent_drafts', __('Recent Drafts'), 'wp_dashboard_recent_drafts' );
84
85         // Primary feed (Dev Blog) Widget
86         if ( !isset( $widget_options['dashboard_primary'] ) ) {
87                 $update = true;
88                 $widget_options['dashboard_primary'] = array(
89                         'link' => apply_filters( 'dashboard_primary_link', __( 'http://wordpress.org/news/' ) ),
90                         'url' => apply_filters( 'dashboard_primary_feed', __( 'http://wordpress.org/news/feed/' ) ),
91                         'title' => apply_filters( 'dashboard_primary_title', __( 'WordPress Blog' ) ),
92                         'items' => 2,
93                         'show_summary' => 1,
94                         'show_author' => 0,
95                         'show_date' => 1,
96                 );
97         }
98         wp_add_dashboard_widget( 'dashboard_primary', $widget_options['dashboard_primary']['title'], 'wp_dashboard_primary', 'wp_dashboard_primary_control' );
99
100         // Secondary Feed (Planet) Widget
101         if ( !isset( $widget_options['dashboard_secondary'] ) ) {
102                 $update = true;
103                 $widget_options['dashboard_secondary'] = array(
104                         'link' => apply_filters( 'dashboard_secondary_link', __( 'http://planet.wordpress.org/' ) ),
105                         'url' => apply_filters( 'dashboard_secondary_feed', __( 'http://planet.wordpress.org/feed/' ) ),
106                         'title' => apply_filters( 'dashboard_secondary_title', __( 'Other WordPress News' ) ),
107                         'items' => 5,
108                         'show_summary' => 0,
109                         'show_author' => 0,
110                         'show_date' => 0,
111                 );
112         }
113         wp_add_dashboard_widget( 'dashboard_secondary', $widget_options['dashboard_secondary']['title'], 'wp_dashboard_secondary', 'wp_dashboard_secondary_control' );
114
115         // Hook to register new widgets
116         // Filter widget order
117         if ( is_network_admin() ) {
118                 do_action( 'wp_network_dashboard_setup' );
119                 $dashboard_widgets = apply_filters( 'wp_network_dashboard_widgets', array() );
120         } elseif ( is_user_admin() ) {
121                 do_action( 'wp_user_dashboard_setup' );
122                 $dashboard_widgets = apply_filters( 'wp_user_dashboard_widgets', array() );
123         } else {
124                 do_action( 'wp_dashboard_setup' );
125                 $dashboard_widgets = apply_filters( 'wp_dashboard_widgets', array() );
126         }
127
128         foreach ( $dashboard_widgets as $widget_id ) {
129                 $name = empty( $wp_registered_widgets[$widget_id]['all_link'] ) ? $wp_registered_widgets[$widget_id]['name'] : $wp_registered_widgets[$widget_id]['name'] . " <a href='{$wp_registered_widgets[$widget_id]['all_link']}' class='edit-box open-box'>" . __('View all') . '</a>';
130                 wp_add_dashboard_widget( $widget_id, $name, $wp_registered_widgets[$widget_id]['callback'], $wp_registered_widget_controls[$widget_id]['callback'] );
131         }
132
133         if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget_id']) ) {
134                 ob_start(); // hack - but the same hack wp-admin/widgets.php uses
135                 wp_dashboard_trigger_widget_control( $_POST['widget_id'] );
136                 ob_end_clean();
137                 wp_redirect( remove_query_arg( 'edit' ) );
138                 exit;
139         }
140
141         if ( $update )
142                 update_option( 'dashboard_widget_options', $widget_options );
143
144         do_action('do_meta_boxes', $screen->id, 'normal', '');
145         do_action('do_meta_boxes', $screen->id, 'side', '');
146 }
147
148 function wp_add_dashboard_widget( $widget_id, $widget_name, $callback, $control_callback = null ) {
149         $screen = get_current_screen();
150         global $wp_dashboard_control_callbacks;
151
152         if ( $control_callback && current_user_can( 'edit_dashboard' ) && is_callable( $control_callback ) ) {
153                 $wp_dashboard_control_callbacks[$widget_id] = $control_callback;
154                 if ( isset( $_GET['edit'] ) && $widget_id == $_GET['edit'] ) {
155                         list($url) = explode( '#', add_query_arg( 'edit', false ), 2 );
156                         $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( $url ) . '">' . __( 'Cancel' ) . '</a></span>';
157                         $callback = '_wp_dashboard_control_callback';
158                 } else {
159                         list($url) = explode( '#', add_query_arg( 'edit', $widget_id ), 2 );
160                         $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( "$url#$widget_id" ) . '" class="edit-box open-box">' . __( 'Configure' ) . '</a></span>';
161                 }
162         }
163
164         if ( is_blog_admin () )
165                 $side_widgets = array('dashboard_quick_press', 'dashboard_recent_drafts', 'dashboard_primary', 'dashboard_secondary');
166         else if (is_network_admin() )
167                 $side_widgets = array('dashboard_primary', 'dashboard_secondary');
168         else
169                 $side_widgets = array();
170
171         $location = 'normal';
172         if ( in_array($widget_id, $side_widgets) )
173                 $location = 'side';
174
175         $priority = 'core';
176         if ( 'dashboard_browser_nag' === $widget_id )
177                 $priority = 'high';
178
179         add_meta_box( $widget_id, $widget_name, $callback, $screen, $location, $priority );
180 }
181
182 function _wp_dashboard_control_callback( $dashboard, $meta_box ) {
183         echo '<form action="" method="post" class="dashboard-widget-control-form">';
184         wp_dashboard_trigger_widget_control( $meta_box['id'] );
185         echo '<input type="hidden" name="widget_id" value="' . esc_attr($meta_box['id']) . '" />';
186         submit_button( __('Submit') );
187         echo '</form>';
188 }
189
190 /**
191  * Displays the dashboard.
192  *
193  * @since 2.5.0
194  */
195 function wp_dashboard() {
196         $screen = get_current_screen();
197         $class = 'columns-' . get_current_screen()->get_columns();
198
199 ?>
200 <div id="dashboard-widgets" class="metabox-holder <?php echo $class; ?>">
201         <div id='postbox-container-1' class='postbox-container'>
202         <?php do_meta_boxes( $screen->id, 'normal', '' ); ?>
203         </div>
204         <div id='postbox-container-2' class='postbox-container'>
205         <?php do_meta_boxes( $screen->id, 'side', '' ); ?>
206         </div>
207         <div id='postbox-container-3' class='postbox-container'>
208         <?php do_meta_boxes( $screen->id, 'column3', '' ); ?>
209         </div>
210         <div id='postbox-container-4' class='postbox-container'>
211         <?php do_meta_boxes( $screen->id, 'column4', '' ); ?>
212         </div>
213 </div>
214
215 <?php
216         wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
217         wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
218
219 }
220
221 /* Dashboard Widgets */
222
223 function wp_dashboard_right_now() {
224         global $wp_registered_sidebars;
225
226         $num_posts = wp_count_posts( 'post' );
227         $num_pages = wp_count_posts( 'page' );
228
229         $num_cats  = wp_count_terms('category');
230
231         $num_tags = wp_count_terms('post_tag');
232
233         $num_comm = wp_count_comments( );
234
235         echo "\n\t".'<div class="table table_content">';
236         echo "\n\t".'<p class="sub">' . __('Content') . '</p>'."\n\t".'<table>';
237         echo "\n\t".'<tr class="first">';
238
239         // Posts
240         $num = number_format_i18n( $num_posts->publish );
241         $text = _n( 'Post', 'Posts', intval($num_posts->publish) );
242         if ( current_user_can( 'edit_posts' ) ) {
243                 $num = "<a href='edit.php'>$num</a>";
244                 $text = "<a href='edit.php'>$text</a>";
245         }
246         echo '<td class="first b b-posts">' . $num . '</td>';
247         echo '<td class="t posts">' . $text . '</td>';
248
249         echo '</tr><tr>';
250         /* TODO: Show status breakdown on hover
251         if ( $can_edit_pages && !empty($num_pages->publish) ) { // how many pages is not exposed in feeds. Don't show if !current_user_can
252                 $post_type_texts[] = '<a href="edit-pages.php">'.sprintf( _n( '%s page', '%s pages', $num_pages->publish ), number_format_i18n( $num_pages->publish ) ).'</a>';
253         }
254         if ( $can_edit_posts && !empty($num_posts->draft) ) {
255                 $post_type_texts[] = '<a href="edit.php?post_status=draft">'.sprintf( _n( '%s draft', '%s drafts', $num_posts->draft ), number_format_i18n( $num_posts->draft ) ).'</a>';
256         }
257         if ( $can_edit_posts && !empty($num_posts->future) ) {
258                 $post_type_texts[] = '<a href="edit.php?post_status=future">'.sprintf( _n( '%s scheduled post', '%s scheduled posts', $num_posts->future ), number_format_i18n( $num_posts->future ) ).'</a>';
259         }
260         if ( current_user_can('publish_posts') && !empty($num_posts->pending) ) {
261                 $pending_text = sprintf( _n( 'There is <a href="%1$s">%2$s post</a> pending your review.', 'There are <a href="%1$s">%2$s posts</a> pending your review.', $num_posts->pending ), 'edit.php?post_status=pending', number_format_i18n( $num_posts->pending ) );
262         } else {
263                 $pending_text = '';
264         }
265         */
266
267         // Pages
268         $num = number_format_i18n( $num_pages->publish );
269         $text = _n( 'Page', 'Pages', $num_pages->publish );
270         if ( current_user_can( 'edit_pages' ) ) {
271                 $num = "<a href='edit.php?post_type=page'>$num</a>";
272                 $text = "<a href='edit.php?post_type=page'>$text</a>";
273         }
274         echo '<td class="first b b_pages">' . $num . '</td>';
275         echo '<td class="t pages">' . $text . '</td>';
276
277         echo '</tr><tr>';
278
279         // Categories
280         $num = number_format_i18n( $num_cats );
281         $text = _n( 'Category', 'Categories', $num_cats );
282         if ( current_user_can( 'manage_categories' ) ) {
283                 $num = "<a href='edit-tags.php?taxonomy=category'>$num</a>";
284                 $text = "<a href='edit-tags.php?taxonomy=category'>$text</a>";
285         }
286         echo '<td class="first b b-cats">' . $num . '</td>';
287         echo '<td class="t cats">' . $text . '</td>';
288
289         echo '</tr><tr>';
290
291         // Tags
292         $num = number_format_i18n( $num_tags );
293         $text = _n( 'Tag', 'Tags', $num_tags );
294         if ( current_user_can( 'manage_categories' ) ) {
295                 $num = "<a href='edit-tags.php'>$num</a>";
296                 $text = "<a href='edit-tags.php'>$text</a>";
297         }
298         echo '<td class="first b b-tags">' . $num . '</td>';
299         echo '<td class="t tags">' . $text . '</td>';
300
301         echo "</tr>";
302         do_action('right_now_content_table_end');
303         echo "\n\t</table>\n\t</div>";
304
305         echo "\n\t".'<div class="table table_discussion">';
306         echo "\n\t".'<p class="sub">' . __('Discussion') . '</p>'."\n\t".'<table>';
307         echo "\n\t".'<tr class="first">';
308
309         // Total Comments
310         $num = '<span class="total-count">' . number_format_i18n($num_comm->total_comments) . '</span>';
311         $text = _n( 'Comment', 'Comments', $num_comm->total_comments );
312         if ( current_user_can( 'moderate_comments' ) ) {
313                 $num = '<a href="edit-comments.php">' . $num . '</a>';
314                 $text = '<a href="edit-comments.php">' . $text . '</a>';
315         }
316         echo '<td class="b b-comments">' . $num . '</td>';
317         echo '<td class="last t comments">' . $text . '</td>';
318
319         echo '</tr><tr>';
320
321         // Approved Comments
322         $num = '<span class="approved-count">' . number_format_i18n($num_comm->approved) . '</span>';
323         $text = _nx( 'Approved', 'Approved', $num_comm->approved, 'Right Now' );
324         if ( current_user_can( 'moderate_comments' ) ) {
325                 $num = "<a href='edit-comments.php?comment_status=approved'>$num</a>";
326                 $text = "<a class='approved' href='edit-comments.php?comment_status=approved'>$text</a>";
327         }
328         echo '<td class="b b_approved">' . $num . '</td>';
329         echo '<td class="last t">' . $text . '</td>';
330
331         echo "</tr>\n\t<tr>";
332
333         // Pending Comments
334         $num = '<span class="pending-count">' . number_format_i18n($num_comm->moderated) . '</span>';
335         $text = _n( 'Pending', 'Pending', $num_comm->moderated );
336         if ( current_user_can( 'moderate_comments' ) ) {
337                 $num = "<a href='edit-comments.php?comment_status=moderated'>$num</a>";
338                 $text = "<a class='waiting' href='edit-comments.php?comment_status=moderated'>$text</a>";
339         }
340         echo '<td class="b b-waiting">' . $num . '</td>';
341         echo '<td class="last t">' . $text . '</td>';
342
343         echo "</tr>\n\t<tr>";
344
345         // Spam Comments
346         $num = number_format_i18n($num_comm->spam);
347         $text = _nx( 'Spam', 'Spam', $num_comm->spam, 'comment' );
348         if ( current_user_can( 'moderate_comments' ) ) {
349                 $num = "<a href='edit-comments.php?comment_status=spam'><span class='spam-count'>$num</span></a>";
350                 $text = "<a class='spam' href='edit-comments.php?comment_status=spam'>$text</a>";
351         }
352         echo '<td class="b b-spam">' . $num . '</td>';
353         echo '<td class="last t">' . $text . '</td>';
354
355         echo "</tr>";
356         do_action('right_now_table_end');
357         do_action('right_now_discussion_table_end');
358         echo "\n\t</table>\n\t</div>";
359
360         echo "\n\t".'<div class="versions">';
361         $theme = wp_get_theme();
362
363         echo "\n\t<p>";
364
365         if ( $theme->errors() ) {
366                 if ( ! is_multisite() || is_super_admin() )
367                         echo '<span class="error-message">' . __('ERROR: The themes directory is either empty or doesn&#8217;t exist. Please check your installation.') . '</span>';
368         } elseif ( ! empty($wp_registered_sidebars) ) {
369                 $sidebars_widgets = wp_get_sidebars_widgets();
370                 $num_widgets = 0;
371                 foreach ( (array) $sidebars_widgets as $k => $v ) {
372                         if ( 'wp_inactive_widgets' == $k || 'orphaned_widgets' == substr( $k, 0, 16 ) )
373                                 continue;
374                         if ( is_array($v) )
375                                 $num_widgets = $num_widgets + count($v);
376                 }
377                 $num = number_format_i18n( $num_widgets );
378
379                 $switch_themes = $theme->display('Name');
380                 if ( current_user_can( 'switch_themes') )
381                         $switch_themes = '<a href="themes.php">' . $switch_themes . '</a>';
382                 if ( current_user_can( 'edit_theme_options' ) ) {
383                         printf(_n('Theme <span class="b">%1$s</span> with <span class="b"><a href="widgets.php">%2$s Widget</a></span>', 'Theme <span class="b">%1$s</span> with <span class="b"><a href="widgets.php">%2$s Widgets</a></span>', $num_widgets), $switch_themes, $num);
384                 } else {
385                         printf(_n('Theme <span class="b">%1$s</span> with <span class="b">%2$s Widget</span>', 'Theme <span class="b">%1$s</span> with <span class="b">%2$s Widgets</span>', $num_widgets), $switch_themes, $num);
386                 }
387         } else {
388                 if ( current_user_can( 'switch_themes' ) )
389                         printf( __('Theme <span class="b"><a href="themes.php">%1$s</a></span>'), $theme->display('Name') );
390                 else
391                         printf( __('Theme <span class="b">%1$s</span>'), $theme->display('Name') );
392         }
393         echo '</p>';
394
395         // Check if search engines are blocked.
396         if ( !is_network_admin() && !is_user_admin() && current_user_can('manage_options') && '1' != get_option('blog_public') ) {
397                 $title = apply_filters('privacy_on_link_title', __('Your site is asking search engines not to index its content') );
398                 $content = apply_filters('privacy_on_link_text', __('Search Engines Blocked') );
399
400                 echo "<p><a href='options-privacy.php' title='$title'>$content</a></p>";
401         }
402
403         update_right_now_message();
404
405         echo "\n\t".'<br class="clear" /></div>';
406         do_action( 'rightnow_end' );
407         do_action( 'activity_box_end' );
408 }
409
410 function wp_network_dashboard_right_now() {
411         $actions = array();
412         if ( current_user_can('create_sites') )
413                 $actions['create-site'] = '<a href="' . network_admin_url('site-new.php') . '">' . __( 'Create a New Site' ) . '</a>';
414         if ( current_user_can('create_users') )
415                 $actions['create-user'] = '<a href="' . network_admin_url('user-new.php') . '">' . __( 'Create a New User' ) . '</a>';
416
417         $c_users = get_user_count();
418         $c_blogs = get_blog_count();
419
420         $user_text = sprintf( _n( '%s user', '%s users', $c_users ), number_format_i18n( $c_users ) );
421         $blog_text = sprintf( _n( '%s site', '%s sites', $c_blogs ), number_format_i18n( $c_blogs ) );
422
423         $sentence = sprintf( __( 'You have %1$s and %2$s.' ), $blog_text, $user_text );
424
425         if ( $actions ) {
426                 echo '<ul class="subsubsub">';
427                 foreach ( $actions as $class => $action ) {
428                          $actions[ $class ] = "\t<li class='$class'>$action";
429                 }
430                 echo implode( " |</li>\n", $actions ) . "</li>\n";
431                 echo '</ul>';
432         }
433 ?>
434         <br class="clear" />
435
436         <p class="youhave"><?php echo $sentence; ?></p>
437         <?php do_action( 'wpmuadminresult', '' ); ?>
438
439         <form action="<?php echo network_admin_url('users.php'); ?>" method="get">
440                 <p>
441                         <input type="search" name="s" value="" size="30" autocomplete="off" />
442                         <?php submit_button( __( 'Search Users' ), 'button', 'submit', false, array( 'id' => 'submit_users' ) ); ?>
443                 </p>
444         </form>
445
446         <form action="<?php echo network_admin_url('sites.php'); ?>" method="get">
447                 <p>
448                         <input type="search" name="s" value="" size="30" autocomplete="off" />
449                         <?php submit_button( __( 'Search Sites' ), 'button', 'submit', false, array( 'id' => 'submit_sites' ) ); ?>
450                 </p>
451         </form>
452 <?php
453         do_action( 'mu_rightnow_end' );
454         do_action( 'mu_activity_box_end' );
455 }
456
457 function wp_dashboard_quick_press() {
458         global $post_ID;
459
460         $drafts = false;
461         if ( 'post' === strtolower( $_SERVER['REQUEST_METHOD'] ) && isset( $_POST['action'] ) && 0 === strpos( $_POST['action'], 'post-quickpress' ) && (int) $_POST['post_ID'] ) {
462                 $view = get_permalink( $_POST['post_ID'] );
463                 $edit = esc_url( get_edit_post_link( $_POST['post_ID'] ) );
464                 if ( 'post-quickpress-publish' == $_POST['action'] ) {
465                         if ( current_user_can('publish_posts') )
466                                 printf( '<div class="updated"><p>' . __( 'Post published. <a href="%s">View post</a> | <a href="%s">Edit post</a>' ) . '</p></div>', esc_url( $view ), $edit );
467                         else
468                                 printf( '<div class="updated"><p>' . __( 'Post submitted. <a href="%s">Preview post</a> | <a href="%s">Edit post</a>' ) . '</p></div>', esc_url( add_query_arg( 'preview', 1, $view ) ), $edit );
469                 } else {
470                         printf( '<div class="updated"><p>' . __( 'Draft saved. <a href="%s">Preview post</a> | <a href="%s">Edit post</a>' ) . '</p></div>', esc_url( add_query_arg( 'preview', 1, $view ) ), $edit );
471                         $drafts_query = new WP_Query( array(
472                                 'post_type' => 'post',
473                                 'post_status' => 'draft',
474                                 'author' => $GLOBALS['current_user']->ID,
475                                 'posts_per_page' => 1,
476                                 'orderby' => 'modified',
477                                 'order' => 'DESC'
478                         ) );
479
480                         if ( $drafts_query->posts )
481                                 $drafts =& $drafts_query->posts;
482                 }
483                 printf('<p class="textright">' . __('You can also try %s, easy blogging from anywhere on the Web.') . '</p>', '<a href="' . esc_url( admin_url( 'tools.php' ) ) . '">' . __('Press This') . '</a>' );
484                 $_REQUEST = array(); // hack for get_default_post_to_edit()
485         }
486
487         /* Check if a new auto-draft (= no new post_ID) is needed or if the old can be used */
488         $last_post_id = (int) get_user_option( 'dashboard_quick_press_last_post_id' ); // Get the last post_ID
489         if ( $last_post_id ) {
490                 $post = get_post( $last_post_id );
491                 if ( empty( $post ) || $post->post_status != 'auto-draft' ) { // auto-draft doesn't exists anymore
492                         $post = get_default_post_to_edit('post', true);
493                         update_user_option( (int) $GLOBALS['current_user']->ID, 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID
494                 } else {
495                         $post->post_title = ''; // Remove the auto draft title
496                 }
497         } else {
498                 $post = get_default_post_to_edit('post', true);
499                 update_user_option( (int) $GLOBALS['current_user']->ID, 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID
500         }
501
502         $post_ID = (int) $post->ID;
503 ?>
504
505         <form name="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>" method="post" id="quick-press">
506                 <h4 id="quick-post-title"><label for="title"><?php _e('Title') ?></label></h4>
507                 <div class="input-text-wrap">
508                         <input type="text" name="post_title" id="title" tabindex="1" autocomplete="off" value="<?php echo esc_attr( $post->post_title ); ?>" />
509                 </div>
510
511                 <?php if ( current_user_can( 'upload_files' ) ) : ?>
512                 <div id="wp-content-wrap" class="wp-editor-wrap hide-if-no-js wp-media-buttons">
513                         <?php do_action( 'media_buttons', 'content' ); ?>
514                 </div>
515                 <?php endif; ?>
516
517                 <h4 id="content-label"><label for="content"><?php _e('Content') ?></label></h4>
518                 <div class="textarea-wrap">
519                         <textarea name="content" id="content" class="mceEditor" rows="3" cols="15" tabindex="2"><?php echo esc_textarea( $post->post_content ); ?></textarea>
520                 </div>
521
522                 <script type="text/javascript">edCanvas = document.getElementById('content');edInsertContent = null;</script>
523
524                 <h4><label for="tags-input"><?php _e('Tags') ?></label></h4>
525                 <div class="input-text-wrap">
526                         <input type="text" name="tags_input" id="tags-input" tabindex="3" value="<?php echo get_tags_to_edit( $post->ID ); ?>" />
527                 </div>
528
529                 <p class="submit">
530                         <input type="hidden" name="action" id="quickpost-action" value="post-quickpress-save" />
531                         <input type="hidden" name="post_ID" value="<?php echo $post_ID; ?>" />
532                         <input type="hidden" name="post_type" value="post" />
533                         <?php wp_nonce_field('add-post'); ?>
534                         <?php submit_button( __( 'Save Draft' ), 'button', 'save', false, array( 'id' => 'save-post', 'tabindex'=> 4 ) ); ?>
535                         <input type="reset" value="<?php esc_attr_e( 'Reset' ); ?>" class="button" />
536                         <span id="publishing-action">
537                                 <input type="submit" name="publish" id="publish" accesskey="p" tabindex="5" class="button-primary" value="<?php current_user_can('publish_posts') ? esc_attr_e('Publish') : esc_attr_e('Submit for Review'); ?>" />
538                                 <img class="waiting" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
539                         </span>
540                         <br class="clear" />
541                 </p>
542
543         </form>
544
545 <?php
546         if ( $drafts )
547                 wp_dashboard_recent_drafts( $drafts );
548 }
549
550 function wp_dashboard_recent_drafts( $drafts = false ) {
551         if ( !$drafts ) {
552                 $drafts_query = new WP_Query( array(
553                         'post_type' => 'post',
554                         'post_status' => 'draft',
555                         'author' => $GLOBALS['current_user']->ID,
556                         'posts_per_page' => 5,
557                         'orderby' => 'modified',
558                         'order' => 'DESC'
559                 ) );
560                 $drafts =& $drafts_query->posts;
561         }
562
563         if ( $drafts && is_array( $drafts ) ) {
564                 $list = array();
565                 foreach ( $drafts as $draft ) {
566                         $url = get_edit_post_link( $draft->ID );
567                         $title = _draft_or_post_title( $draft->ID );
568                         $item = "<h4><a href='$url' title='" . sprintf( __( 'Edit &#8220;%s&#8221;' ), esc_attr( $title ) ) . "'>" . esc_html($title) . "</a> <abbr title='" . get_the_time(__('Y/m/d g:i:s A'), $draft) . "'>" . get_the_time( get_option( 'date_format' ), $draft ) . '</abbr></h4>';
569                         if ( $the_content = preg_split( '#\s#', strip_tags( $draft->post_content ), 11, PREG_SPLIT_NO_EMPTY ) )
570                                 $item .= '<p>' . join( ' ', array_slice( $the_content, 0, 10 ) ) . ( 10 < count( $the_content ) ? '&hellip;' : '' ) . '</p>';
571                         $list[] = $item;
572                 }
573 ?>
574         <ul>
575                 <li><?php echo join( "</li>\n<li>", $list ); ?></li>
576         </ul>
577         <p class="textright"><a href="edit.php?post_status=draft" ><?php _e('View all'); ?></a></p>
578 <?php
579         } else {
580                 _e('There are no drafts at the moment');
581         }
582 }
583
584 /**
585  * Display recent comments dashboard widget content.
586  *
587  * @since 2.5.0
588  */
589 function wp_dashboard_recent_comments() {
590         global $wpdb;
591
592         // Select all comment types and filter out spam later for better query performance.
593         $comments = array();
594         $start = 0;
595
596         $widgets = get_option( 'dashboard_widget_options' );
597         $total_items = isset( $widgets['dashboard_recent_comments'] ) && isset( $widgets['dashboard_recent_comments']['items'] )
598                 ? absint( $widgets['dashboard_recent_comments']['items'] ) : 5;
599
600         $comments_query = array( 'number' => $total_items * 5, 'offset' => 0 );
601         if ( ! current_user_can( 'edit_posts' ) )
602                 $comments_query['status'] = 'approve';
603
604         while ( count( $comments ) < $total_items && $possible = get_comments( $comments_query ) ) {
605                 foreach ( $possible as $comment ) {
606                         if ( ! current_user_can( 'read_post', $comment->comment_post_ID ) )
607                                 continue;
608                         $comments[] = $comment;
609                         if ( count( $comments ) == $total_items )
610                                 break 2;
611                 }
612                 $comments_query['offset'] += $comments_query['number'];
613                 $comments_query['number'] = $total_items * 10;
614         }
615
616         if ( $comments ) {
617                 echo '<div id="the-comment-list" class="list:comment">';
618                 foreach ( $comments as $comment )
619                         _wp_dashboard_recent_comments_row( $comment );
620                 echo '</div>';
621
622                 if ( current_user_can('edit_posts') )
623                         _get_list_table('WP_Comments_List_Table')->views();
624
625                 wp_comment_reply( -1, false, 'dashboard', false );
626                 wp_comment_trashnotice();
627         } else {
628                 echo '<p>' . __( 'No comments yet.' ) . '</p>';
629         }
630 }
631
632 function _wp_dashboard_recent_comments_row( &$comment, $show_date = true ) {
633         $GLOBALS['comment'] =& $comment;
634
635         $comment_post_url = get_edit_post_link( $comment->comment_post_ID );
636         $comment_post_title = strip_tags(get_the_title( $comment->comment_post_ID ));
637         $comment_post_link = "<a href='$comment_post_url'>$comment_post_title</a>";
638         $comment_link = '<a class="comment-link" href="' . esc_url(get_comment_link()) . '">#</a>';
639
640         $actions_string = '';
641         if ( current_user_can( 'edit_comment', $comment->comment_ID ) ) {
642                 // preorder it: Approve | Reply | Edit | Spam | Trash
643                 $actions = array(
644                         'approve' => '', 'unapprove' => '',
645                         'reply' => '',
646                         'edit' => '',
647                         'spam' => '',
648                         'trash' => '', 'delete' => ''
649                 );
650
651                 $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
652                 $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
653
654                 $approve_url = esc_url( "comment.php?action=approvecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$approve_nonce" );
655                 $unapprove_url = esc_url( "comment.php?action=unapprovecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$approve_nonce" );
656                 $spam_url = esc_url( "comment.php?action=spamcomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
657                 $trash_url = esc_url( "comment.php?action=trashcomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
658                 $delete_url = esc_url( "comment.php?action=deletecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
659
660                 $actions['approve'] = "<a href='$approve_url' class='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved vim-a' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
661                 $actions['unapprove'] = "<a href='$unapprove_url' class='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved vim-u' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
662                 $actions['edit'] = "<a href='comment.php?action=editcomment&amp;c={$comment->comment_ID}' title='" . esc_attr__('Edit comment') . "'>". __('Edit') . '</a>';
663                 $actions['reply'] = '<a onclick="commentReply.open(\''.$comment->comment_ID.'\',\''.$comment->comment_post_ID.'\');return false;" class="vim-r hide-if-no-js" title="'.esc_attr__('Reply to this comment').'" href="#">' . __('Reply') . '</a>';
664                 $actions['spam'] = "<a href='$spam_url' class='delete:the-comment-list:comment-$comment->comment_ID::spam=1 vim-s vim-destructive' title='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
665                 if ( !EMPTY_TRASH_DAYS )
666                         $actions['delete'] = "<a href='$delete_url' class='delete:the-comment-list:comment-$comment->comment_ID::trash=1 delete vim-d vim-destructive'>" . __('Delete Permanently') . '</a>';
667                 else
668                         $actions['trash'] = "<a href='$trash_url' class='delete:the-comment-list:comment-$comment->comment_ID::trash=1 delete vim-d vim-destructive' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x('Trash', 'verb') . '</a>';
669
670                 $actions = apply_filters( 'comment_row_actions', array_filter($actions), $comment );
671
672                 $i = 0;
673                 foreach ( $actions as $action => $link ) {
674                         ++$i;
675                         ( ( ('approve' == $action || 'unapprove' == $action) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
676
677                         // Reply and quickedit need a hide-if-no-js span
678                         if ( 'reply' == $action || 'quickedit' == $action )
679                                 $action .= ' hide-if-no-js';
680
681                         $actions_string .= "<span class='$action'>$sep$link</span>";
682                 }
683         }
684
685 ?>
686
687                 <div id="comment-<?php echo $comment->comment_ID; ?>" <?php comment_class( array( 'comment-item', wp_get_comment_status($comment->comment_ID) ) ); ?>>
688                         <?php if ( !$comment->comment_type || 'comment' == $comment->comment_type ) : ?>
689
690                         <?php echo get_avatar( $comment, 50 ); ?>
691
692                         <div class="dashboard-comment-wrap">
693                         <h4 class="comment-meta">
694                                 <?php printf( /* translators: 1: comment author, 2: post link, 3: notification if the comment is pending */__( 'From %1$s on %2$s%3$s' ),
695                                         '<cite class="comment-author">' . get_comment_author_link() . '</cite>', $comment_post_link.' '.$comment_link, ' <span class="approve">' . __( '[Pending]' ) . '</span>' ); ?>
696                         </h4>
697
698                         <?php
699                         else :
700                                 switch ( $comment->comment_type ) :
701                                 case 'pingback' :
702                                         $type = __( 'Pingback' );
703                                         break;
704                                 case 'trackback' :
705                                         $type = __( 'Trackback' );
706                                         break;
707                                 default :
708                                         $type = ucwords( $comment->comment_type );
709                                 endswitch;
710                                 $type = esc_html( $type );
711                         ?>
712                         <div class="dashboard-comment-wrap">
713                         <?php /* translators: %1$s is type of comment, %2$s is link to the post */ ?>
714                         <h4 class="comment-meta"><?php printf( _x( '%1$s on %2$s', 'dashboard' ), "<strong>$type</strong>", $comment_post_link." ".$comment_link ); ?></h4>
715                         <p class="comment-author"><?php comment_author_link(); ?></p>
716
717                         <?php endif; // comment_type ?>
718                         <blockquote><p><?php comment_excerpt(); ?></p></blockquote>
719                         <p class="row-actions"><?php echo $actions_string; ?></p>
720                         </div>
721                 </div>
722 <?php
723 }
724
725 /**
726  * The recent comments dashboard widget control.
727  *
728  * @since 3.0.0
729  */
730 function wp_dashboard_recent_comments_control() {
731         if ( !$widget_options = get_option( 'dashboard_widget_options' ) )
732                 $widget_options = array();
733
734         if ( !isset($widget_options['dashboard_recent_comments']) )
735                 $widget_options['dashboard_recent_comments'] = array();
736
737         if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget-recent-comments']) ) {
738                 $number = absint( $_POST['widget-recent-comments']['items'] );
739                 $widget_options['dashboard_recent_comments']['items'] = $number;
740                 update_option( 'dashboard_widget_options', $widget_options );
741         }
742
743         $number = isset( $widget_options['dashboard_recent_comments']['items'] ) ? (int) $widget_options['dashboard_recent_comments']['items'] : '';
744
745         echo '<p><label for="comments-number">' . __('Number of comments to show:') . '</label>';
746         echo '<input id="comments-number" name="widget-recent-comments[items]" type="text" value="' . $number . '" size="3" /></p>';
747 }
748
749 function wp_dashboard_incoming_links() {
750         wp_dashboard_cached_rss_widget( 'dashboard_incoming_links', 'wp_dashboard_incoming_links_output' );
751 }
752
753 /**
754  * Display incoming links dashboard widget content.
755  *
756  * @since 2.5.0
757  */
758 function wp_dashboard_incoming_links_output() {
759         $widgets = get_option( 'dashboard_widget_options' );
760         @extract( @$widgets['dashboard_incoming_links'], EXTR_SKIP );
761         $rss = fetch_feed( $url );
762
763         if ( is_wp_error($rss) ) {
764                 if ( is_admin() || current_user_can('manage_options') ) {
765                         echo '<p>';
766                         printf(__('<strong>RSS Error</strong>: %s'), $rss->get_error_message());
767                         echo '</p>';
768                 }
769                 return;
770         }
771
772         if ( !$rss->get_item_quantity() ) {
773                 echo '<p>' . __('This dashboard widget queries <a href="http://blogsearch.google.com/">Google Blog Search</a> so that when another blog links to your site it will show up here. It has found no incoming links&hellip; yet. It&#8217;s okay &#8212; there is no rush.') . "</p>\n";
774                 $rss->__destruct();
775                 unset($rss);
776                 return;
777         }
778
779         echo "<ul>\n";
780
781         if ( !isset($items) )
782                 $items = 10;
783
784         foreach ( $rss->get_items(0, $items) as $item ) {
785                 $publisher = '';
786                 $site_link = '';
787                 $link = '';
788                 $content = '';
789                 $date = '';
790                 $link = esc_url( strip_tags( $item->get_link() ) );
791
792                 $author = $item->get_author();
793                 if ( $author ) {
794                         $site_link = esc_url( strip_tags( $author->get_link() ) );
795
796                         if ( !$publisher = esc_html( strip_tags( $author->get_name() ) ) )
797                                 $publisher = __( 'Somebody' );
798                 } else {
799                   $publisher = __( 'Somebody' );
800                 }
801                 if ( $site_link )
802                         $publisher = "<a href='$site_link'>$publisher</a>";
803                 else
804                         $publisher = "<strong>$publisher</strong>";
805
806                 $content = $item->get_content();
807                 $content = wp_html_excerpt($content, 50) . ' ...';
808
809                 if ( $link )
810                         /* translators: incoming links feed, %1$s is other person, %3$s is content */
811                         $text = __( '%1$s linked here <a href="%2$s">saying</a>, "%3$s"' );
812                 else
813                         /* translators: incoming links feed, %1$s is other person, %3$s is content */
814                         $text = __( '%1$s linked here saying, "%3$s"' );
815
816                 if ( !empty($show_date) ) {
817                         if ( !empty($show_author) || !empty($show_summary) )
818                                 /* translators: incoming links feed, %4$s is the date */
819                                 $text .= ' ' . __( 'on %4$s' );
820                         $date = esc_html( strip_tags( $item->get_date() ) );
821                         $date = strtotime( $date );
822                         $date = gmdate( get_option( 'date_format' ), $date );
823                 }
824
825                 echo "\t<li>" . sprintf( $text, $publisher, $link, $content, $date ) . "</li>\n";
826         }
827
828         echo "</ul>\n";
829         $rss->__destruct();
830         unset($rss);
831 }
832
833 function wp_dashboard_incoming_links_control() {
834         wp_dashboard_rss_control( 'dashboard_incoming_links', array( 'title' => false, 'show_summary' => false, 'show_author' => false ) );
835 }
836
837 function wp_dashboard_primary() {
838         wp_dashboard_cached_rss_widget( 'dashboard_primary', 'wp_dashboard_rss_output' );
839 }
840
841 function wp_dashboard_primary_control() {
842         wp_dashboard_rss_control( 'dashboard_primary' );
843 }
844
845 /**
846  * {@internal Missing Short Description}}
847  *
848  * @since 2.5.0
849  *
850  * @param string $widget_id
851  */
852 function wp_dashboard_rss_output( $widget_id ) {
853         $widgets = get_option( 'dashboard_widget_options' );
854         echo '<div class="rss-widget">';
855         wp_widget_rss_output( $widgets[$widget_id] );
856         echo "</div>";
857 }
858
859 function wp_dashboard_secondary() {
860         wp_dashboard_cached_rss_widget( 'dashboard_secondary', 'wp_dashboard_secondary_output' );
861 }
862
863 function wp_dashboard_secondary_control() {
864         wp_dashboard_rss_control( 'dashboard_secondary' );
865 }
866
867 /**
868  * Display secondary dashboard RSS widget feed.
869  *
870  * @since 2.5.0
871  *
872  * @return unknown
873  */
874 function wp_dashboard_secondary_output() {
875         $widgets = get_option( 'dashboard_widget_options' );
876         @extract( @$widgets['dashboard_secondary'], EXTR_SKIP );
877         $rss = @fetch_feed( $url );
878
879         if ( is_wp_error($rss) ) {
880                 if ( is_admin() || current_user_can('manage_options') ) {
881                         echo '<div class="rss-widget"><p>';
882                         printf(__('<strong>RSS Error</strong>: %s'), $rss->get_error_message());
883                         echo '</p></div>';
884                 }
885         } elseif ( !$rss->get_item_quantity() ) {
886                 $rss->__destruct();
887                 unset($rss);
888                 return false;
889         } else {
890                 echo '<div class="rss-widget">';
891                 wp_widget_rss_output( $rss, $widgets['dashboard_secondary'] );
892                 echo '</div>';
893                 $rss->__destruct();
894                 unset($rss);
895         }
896 }
897
898 function wp_dashboard_plugins() {
899         wp_dashboard_cached_rss_widget( 'dashboard_plugins', 'wp_dashboard_plugins_output', array(
900                 'http://wordpress.org/extend/plugins/rss/browse/popular/',
901                 'http://wordpress.org/extend/plugins/rss/browse/new/'
902         ) );
903 }
904
905 /**
906  * Display plugins most popular, newest plugins, and recently updated widget text.
907  *
908  * @since 2.5.0
909  */
910 function wp_dashboard_plugins_output() {
911         $popular = fetch_feed( 'http://wordpress.org/extend/plugins/rss/browse/popular/' );
912         $new     = fetch_feed( 'http://wordpress.org/extend/plugins/rss/browse/new/' );
913
914         if ( false === $plugin_slugs = get_transient( 'plugin_slugs' ) ) {
915                 $plugin_slugs = array_keys( get_plugins() );
916                 set_transient( 'plugin_slugs', $plugin_slugs, 86400 );
917         }
918
919         foreach ( array( 'popular' => __('Most Popular'), 'new' => __('Newest Plugins') ) as $feed => $label ) {
920                 if ( is_wp_error($$feed) || !$$feed->get_item_quantity() )
921                         continue;
922
923                 $items = $$feed->get_items(0, 5);
924
925                 // Pick a random, non-installed plugin
926                 while ( true ) {
927                         // Abort this foreach loop iteration if there's no plugins left of this type
928                         if ( 0 == count($items) )
929                                 continue 2;
930
931                         $item_key = array_rand($items);
932                         $item = $items[$item_key];
933
934                         list($link, $frag) = explode( '#', $item->get_link() );
935
936                         $link = esc_url($link);
937                         if ( preg_match( '|/([^/]+?)/?$|', $link, $matches ) )
938                                 $slug = $matches[1];
939                         else {
940                                 unset( $items[$item_key] );
941                                 continue;
942                         }
943
944                         // Is this random plugin's slug already installed? If so, try again.
945                         reset( $plugin_slugs );
946                         foreach ( $plugin_slugs as $plugin_slug ) {
947                                 if ( $slug == substr( $plugin_slug, 0, strlen( $slug ) ) ) {
948                                         unset( $items[$item_key] );
949                                         continue 2;
950                                 }
951                         }
952
953                         // If we get to this point, then the random plugin isn't installed and we can stop the while().
954                         break;
955                 }
956
957                 // Eliminate some common badly formed plugin descriptions
958                 while ( ( null !== $item_key = array_rand($items) ) && false !== strpos( $items[$item_key]->get_description(), 'Plugin Name:' ) )
959                         unset($items[$item_key]);
960
961                 if ( !isset($items[$item_key]) )
962                         continue;
963
964                 // current bbPress feed item titles are: user on "topic title"
965                 if ( preg_match( '/&quot;(.*)&quot;/s', $item->get_title(), $matches ) )
966                         $title = $matches[1];
967                 else // but let's make it forward compatible if things change
968                         $title = $item->get_title();
969                 $title = esc_html( $title );
970
971                 $description = esc_html( strip_tags(@html_entity_decode($item->get_description(), ENT_QUOTES, get_option('blog_charset'))) );
972
973                 $ilink = wp_nonce_url('plugin-install.php?tab=plugin-information&plugin=' . $slug, 'install-plugin_' . $slug) .
974                                                         '&amp;TB_iframe=true&amp;width=600&amp;height=800';
975
976                 echo "<h4>$label</h4>\n";
977                 echo "<h5><a href='$link'>$title</a></h5>&nbsp;<span>(<a href='$ilink' class='thickbox' title='$title'>" . __( 'Install' ) . "</a>)</span>\n";
978                 echo "<p>$description</p>\n";
979
980                 $$feed->__destruct();
981                 unset($$feed);
982         }
983 }
984
985 /**
986  * Checks to see if all of the feed url in $check_urls are cached.
987  *
988  * If $check_urls is empty, look for the rss feed url found in the dashboard
989  * widget options of $widget_id. If cached, call $callback, a function that
990  * echoes out output for this widget. If not cache, echo a "Loading..." stub
991  * which is later replaced by AJAX call (see top of /wp-admin/index.php)
992  *
993  * @since 2.5.0
994  *
995  * @param string $widget_id
996  * @param callback $callback
997  * @param array $check_urls RSS feeds
998  * @return bool False on failure. True on success.
999  */
1000 function wp_dashboard_cached_rss_widget( $widget_id, $callback, $check_urls = array() ) {
1001         $loading = '<p class="widget-loading hide-if-no-js">' . __( 'Loading&#8230;' ) . '</p><p class="hide-if-js">' . __( 'This widget requires JavaScript.' ) . '</p>';
1002         $doing_ajax = ( defined('DOING_AJAX') && DOING_AJAX );
1003
1004         if ( empty($check_urls) ) {
1005                 $widgets = get_option( 'dashboard_widget_options' );
1006                 if ( empty($widgets[$widget_id]['url']) && ! $doing_ajax ) {
1007                         echo $loading;
1008                         return false;
1009                 }
1010                 $check_urls = array( $widgets[$widget_id]['url'] );
1011         }
1012
1013         $cache_key = 'dash_' . md5( $widget_id );
1014         if ( false !== ( $output = get_transient( $cache_key ) ) ) {
1015                 echo $output;
1016                 return true;
1017         }
1018
1019         if ( ! $doing_ajax ) {
1020                 echo $loading;
1021                 return false;
1022         }
1023
1024         if ( $callback && is_callable( $callback ) ) {
1025                 $args = array_slice( func_get_args(), 2 );
1026                 array_unshift( $args, $widget_id );
1027                 ob_start();
1028                 call_user_func_array( $callback, $args );
1029                 set_transient( $cache_key, ob_get_flush(), 43200); // Default lifetime in cache of 12 hours (same as the feeds)
1030         }
1031
1032         return true;
1033 }
1034
1035 /* Dashboard Widgets Controls */
1036
1037 // Calls widget_control callback
1038 /**
1039  * Calls widget control callback.
1040  *
1041  * @since 2.5.0
1042  *
1043  * @param int $widget_control_id Registered Widget ID.
1044  */
1045 function wp_dashboard_trigger_widget_control( $widget_control_id = false ) {
1046         global $wp_dashboard_control_callbacks;
1047
1048         if ( is_scalar($widget_control_id) && $widget_control_id && isset($wp_dashboard_control_callbacks[$widget_control_id]) && is_callable($wp_dashboard_control_callbacks[$widget_control_id]) ) {
1049                 call_user_func( $wp_dashboard_control_callbacks[$widget_control_id], '', array( 'id' => $widget_control_id, 'callback' => $wp_dashboard_control_callbacks[$widget_control_id] ) );
1050         }
1051 }
1052
1053 /**
1054  * The RSS dashboard widget control.
1055  *
1056  * Sets up $args to be used as input to wp_widget_rss_form(). Handles POST data
1057  * from RSS-type widgets.
1058  *
1059  * @since 2.5.0
1060  *
1061  * @param string $widget_id
1062  * @param array $form_inputs
1063  */
1064 function wp_dashboard_rss_control( $widget_id, $form_inputs = array() ) {
1065         if ( !$widget_options = get_option( 'dashboard_widget_options' ) )
1066                 $widget_options = array();
1067
1068         if ( !isset($widget_options[$widget_id]) )
1069                 $widget_options[$widget_id] = array();
1070
1071         $number = 1; // Hack to use wp_widget_rss_form()
1072         $widget_options[$widget_id]['number'] = $number;
1073
1074         if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget-rss'][$number]) ) {
1075                 $_POST['widget-rss'][$number] = stripslashes_deep( $_POST['widget-rss'][$number] );
1076                 $widget_options[$widget_id] = wp_widget_rss_process( $_POST['widget-rss'][$number] );
1077                 // title is optional. If black, fill it if possible
1078                 if ( !$widget_options[$widget_id]['title'] && isset($_POST['widget-rss'][$number]['title']) ) {
1079                         $rss = fetch_feed($widget_options[$widget_id]['url']);
1080                         if ( is_wp_error($rss) ) {
1081                                 $widget_options[$widget_id]['title'] = htmlentities(__('Unknown Feed'));
1082                         } else {
1083                                 $widget_options[$widget_id]['title'] = htmlentities(strip_tags($rss->get_title()));
1084                                 $rss->__destruct();
1085                                 unset($rss);
1086                         }
1087                 }
1088                 update_option( 'dashboard_widget_options', $widget_options );
1089                 $cache_key = 'dash_' . md5( $widget_id );
1090                 delete_transient( $cache_key );
1091         }
1092
1093         wp_widget_rss_form( $widget_options[$widget_id], $form_inputs );
1094 }
1095
1096 // Display File upload quota on dashboard
1097 function wp_dashboard_quota() {
1098         if ( !is_multisite() || !current_user_can('upload_files') || get_site_option( 'upload_space_check_disabled' ) )
1099                 return true;
1100
1101         $quota = get_space_allowed();
1102         $used = get_dirsize( BLOGUPLOADDIR ) / 1024 / 1024;
1103
1104         if ( $used > $quota )
1105                 $percentused = '100';
1106         else
1107                 $percentused = ( $used / $quota ) * 100;
1108         $used_color = ( $percentused >= 70 ) ? ' spam' : '';
1109         $used = round( $used, 2 );
1110         $percentused = number_format( $percentused );
1111
1112         ?>
1113         <p class="sub musub"><?php _e( 'Storage Space' ); ?></p>
1114         <div class="table table_content musubtable">
1115         <table>
1116                 <tr class="first">
1117                         <td class="first b b-posts"><?php printf( __( '<a href="%1$s" title="Manage Uploads" class="musublink">%2$sMB</a>' ), esc_url( admin_url( 'upload.php' ) ), $quota ); ?></td>
1118                         <td class="t posts"><?php _e( 'Space Allowed' ); ?></td>
1119                 </tr>
1120         </table>
1121         </div>
1122         <div class="table table_discussion musubtable">
1123         <table>
1124                 <tr class="first">
1125                         <td class="b b-comments"><?php printf( __( '<a href="%1$s" title="Manage Uploads" class="musublink">%2$sMB (%3$s%%)</a>' ), esc_url( admin_url( 'upload.php' ) ), $used, $percentused ); ?></td>
1126                         <td class="last t comments<?php echo $used_color;?>"><?php _e( 'Space Used' );?></td>
1127                 </tr>
1128         </table>
1129         </div>
1130         <br class="clear" />
1131         <?php
1132 }
1133 add_action( 'activity_box_end', 'wp_dashboard_quota' );
1134
1135 // Display Browser Nag Meta Box
1136 function wp_dashboard_browser_nag() {
1137         $notice = '';
1138         $response = wp_check_browser_version();
1139
1140         if ( $response ) {
1141                 if ( $response['insecure'] ) {
1142                         $msg = sprintf( __( "It looks like you're using an insecure version of <a href='%s'>%s</a>. Using an outdated browser makes your computer unsafe. For the best WordPress experience, please update your browser." ), esc_attr( $response['update_url'] ), esc_html( $response['name'] ) );
1143                 } else {
1144                         $msg = sprintf( __( "It looks like you're using an old version of <a href='%s'>%s</a>. For the best WordPress experience, please update your browser." ), esc_attr( $response['update_url'] ), esc_html( $response['name'] ) );
1145                 }
1146
1147                 $browser_nag_class = '';
1148                 if ( !empty( $response['img_src'] ) ) {
1149                         $img_src = ( is_ssl() && ! empty( $response['img_src_ssl'] ) )? $response['img_src_ssl'] : $response['img_src'];
1150
1151                         $notice .= '<div class="alignright browser-icon"><a href="' . esc_attr($response['update_url']) . '"><img src="' . esc_attr( $img_src ) . '" alt="" /></a></div>';
1152                         $browser_nag_class = ' has-browser-icon';
1153                 }
1154                 $notice .= "<p class='browser-update-nag{$browser_nag_class}'>{$msg}</p>";
1155
1156                 $browsehappy = 'http://browsehappy.com/';
1157                 $locale = get_locale();
1158                 if ( 'en_US' !== $locale )
1159                         $browsehappy = add_query_arg( 'locale', $locale, $browsehappy );
1160
1161                 $notice .= '<p>' . sprintf( __( '<a href="%1$s" class="update-browser-link">Update %2$s</a> or learn how to <a href="%3$s" class="browse-happy-link">browse happy</a>' ), esc_attr( $response['update_url'] ), esc_html( $response['name'] ), esc_url( $browsehappy ) ) . '</p>';
1162                 $notice .= '<p class="hide-if-no-js"><a href="" class="dismiss">' . __( 'Dismiss' ) . '</a></p>';
1163                 $notice .= '<div class="clear"></div>';
1164         }
1165
1166         echo apply_filters( 'browse-happy-notice', $notice, $response );
1167 }
1168
1169 function dashboard_browser_nag_class( $classes ) {
1170         $response = wp_check_browser_version();
1171
1172         if ( $response && $response['insecure'] )
1173                 $classes[] = 'browser-insecure';
1174
1175         return $classes;
1176 }
1177
1178 /**
1179  * Check if the user needs a browser update
1180  *
1181  * @since 3.2.0
1182  *
1183  * @return array|bool False on failure, array of browser data on success.
1184  */
1185 function wp_check_browser_version() {
1186         if ( empty( $_SERVER['HTTP_USER_AGENT'] ) )
1187                 return false;
1188
1189         $key = md5( $_SERVER['HTTP_USER_AGENT'] );
1190
1191         if ( false === ($response = get_site_transient('browser_' . $key) ) ) {
1192                 global $wp_version;
1193
1194                 $options = array(
1195                         'body'                  => array( 'useragent' => $_SERVER['HTTP_USER_AGENT'] ),
1196                         'user-agent'    => 'WordPress/' . $wp_version . '; ' . home_url()
1197                 );
1198
1199                 $response = wp_remote_post( 'http://api.wordpress.org/core/browse-happy/1.0/', $options );
1200
1201                 if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
1202                         return false;
1203
1204                 /**
1205                  * Response should be an array with:
1206                  *  'name' - string - A user friendly browser name
1207                  *  'version' - string - The most recent version of the browser
1208                  *  'current_version' - string - The version of the browser the user is using
1209                  *  'upgrade' - boolean - Whether the browser needs an upgrade
1210                  *  'insecure' - boolean - Whether the browser is deemed insecure
1211                  *  'upgrade_url' - string - The url to visit to upgrade
1212                  *  'img_src' - string - An image representing the browser
1213                  *  'img_src_ssl' - string - An image (over SSL) representing the browser
1214                  */
1215                 $response = maybe_unserialize( wp_remote_retrieve_body( $response ) );
1216
1217                 if ( ! is_array( $response ) )
1218                         return false;
1219
1220                 set_site_transient( 'browser_' . $key, $response, 604800 ); // cache for 1 week
1221         }
1222
1223         return $response;
1224 }
1225
1226 /**
1227  * Empty function usable by plugins to output empty dashboard widget (to be populated later by JS).
1228  */
1229 function wp_dashboard_empty() {}
1230
1231 /**
1232  * Displays a welcome panel to introduce users to WordPress.
1233  *
1234  * @since 3.3.0
1235  */
1236 function wp_welcome_panel() {
1237         global $wp_version;
1238
1239         if ( ! current_user_can( 'edit_theme_options' ) )
1240                 return;
1241
1242         $classes = 'welcome-panel';
1243
1244         $option = get_user_meta( get_current_user_id(), 'show_welcome_panel', true );
1245         // 0 = hide, 1 = toggled to show or single site creator, 2 = multisite site owner
1246         $hide = 0 == $option || ( 2 == $option && wp_get_current_user()->user_email != get_option( 'admin_email' ) );
1247         if ( $hide )
1248                 $classes .= ' hidden';
1249
1250         list( $display_version ) = explode( '-', $wp_version );
1251         ?>
1252         <div id="welcome-panel" class="<?php echo esc_attr( $classes ); ?>">
1253         <?php wp_nonce_field( 'welcome-panel-nonce', 'welcomepanelnonce', false ); ?>
1254         <a class="welcome-panel-close" href="<?php echo esc_url( admin_url( '?welcome=0' ) ); ?>"><?php _e('Dismiss'); ?></a>
1255         <div class="wp-badge"><?php printf( __( 'Version %s' ), $display_version ); ?></div>
1256
1257         <div class="welcome-panel-content">
1258         <h3><?php _e( 'Welcome to your new WordPress site!' ); ?></h3>
1259         <p class="about-description"><?php _e( 'If you need help getting started, check out our documentation on <a href="http://codex.wordpress.org/First_Steps_With_WordPress">First Steps with WordPress</a>. If you&#8217;d rather dive right in, here are a few things most people do first when they set up a new WordPress site. If you need help, use the Help tabs in the upper right corner to get information on how to use your current screen and where to go for more assistance.' ); ?></p>
1260         <div class="welcome-panel-column-container">
1261         <div class="welcome-panel-column">
1262                 <h4><span class="icon16 icon-settings"></span> <?php _e( 'Basic Settings' ); ?></h4>
1263                 <p><?php _e( 'Here are a few easy things you can do to get your feet wet. Make sure to click Save on each Settings screen.' ); ?></p>
1264                 <ul>
1265                 <li><?php echo sprintf( __( '<a href="%s">Choose your privacy setting</a>' ), esc_url( admin_url('options-privacy.php') ) ); ?></li>
1266                 <li><?php echo sprintf( __( '<a href="%s">Select your tagline and time zone</a>' ), esc_url( admin_url('options-general.php') ) ); ?></li>
1267                 <li><?php echo sprintf( __( '<a href="%s">Turn comments on or off</a>' ), esc_url( admin_url('options-discussion.php') ) ); ?></li>
1268                 <li><?php echo sprintf( __( '<a href="%s">Fill in your profile</a>' ), esc_url( admin_url('profile.php') ) ); ?></li>
1269                 </ul>
1270         </div>
1271         <div class="welcome-panel-column">
1272                 <h4><span class="icon16 icon-page"></span> <?php _e( 'Add Real Content' ); ?></h4>
1273                 <p><?php _e( 'Check out the sample page & post editors to see how it all works, then delete the default content and write your own!' ); ?></p>
1274                 <ul>
1275                 <li><?php echo sprintf( __( 'View the <a href="%1$s">sample page</a> and <a href="%2$s">post</a>' ), esc_url( get_permalink( 2 ) ), esc_url( get_permalink( 1 ) ) ); ?></li>
1276                 <li><?php echo sprintf( __( 'Delete the <a href="%1$s">sample page</a> and <a href="%2$s">post</a>' ), esc_url( admin_url('edit.php?post_type=page') ), esc_url( admin_url('edit.php') ) ); ?></li>
1277                 <li><?php echo sprintf( __( '<a href="%s">Create an About Me page</a>' ), esc_url( admin_url('edit.php?post_type=page') ) ); ?></li>
1278                 <li><?php echo sprintf( __( '<a href="%s">Write your first post</a>' ), esc_url( admin_url('post-new.php') ) ); ?></li>
1279                 </ul>
1280         </div>
1281         <div class="welcome-panel-column welcome-panel-last">
1282                 <h4><span class="icon16 icon-appearance"></span> <?php _e( 'Customize Your Site' ); ?></h4>
1283                 <?php
1284                 $theme = wp_get_theme();
1285                 if ( $theme->errors() ) :
1286                         echo '<p>';
1287                         printf( __( '<a href="%s">Install a theme</a> to get started customizing your site.' ), esc_url( admin_url( 'themes.php' ) ) );
1288                         echo '</p>';
1289                 else:
1290                         $customize_links = array();
1291                         if ( 'twentyeleven' == $theme->get_stylesheet() )
1292                                 $customize_links[] = sprintf( __( '<a href="%s">Choose light or dark</a>' ), esc_url( admin_url( 'themes.php?page=theme_options' ) ) );
1293
1294                         if ( current_theme_supports( 'custom-background' ) )
1295                                 $customize_links[] = sprintf( __( '<a href="%s">Set a background color</a>' ), esc_url( admin_url( 'themes.php?page=custom-background' ) ) );
1296
1297                         if ( current_theme_supports( 'custom-header' ) )
1298                                 $customize_links[] = sprintf( __( '<a href="%s">Select a new header image</a>' ), esc_url( admin_url( 'themes.php?page=custom-header' ) ) );
1299
1300                         if ( current_theme_supports( 'widgets' ) )
1301                                 $customize_links[] = sprintf( __( '<a href="%s">Add some widgets</a>' ), esc_url( admin_url( 'widgets.php' ) ) );
1302
1303                         if ( ! empty( $customize_links ) ) {
1304                                 echo '<p>';
1305                                 printf( __( 'Use the current theme &mdash; %1$s &mdash; or <a href="%2$s">choose a new one</a>. If you stick with %1$s, here are a few ways to make your site look unique.' ), $theme->display('Name'), esc_url( admin_url( 'themes.php' ) ) );
1306                                 echo '</p>';
1307                         ?>
1308                         <ul>
1309                                 <?php foreach ( $customize_links as $customize_link ) : ?>
1310                                 <li><?php echo $customize_link ?></li>
1311                                 <?php endforeach; ?>
1312                         </ul>
1313                         <?php
1314                         } else {
1315                                 echo '<p>';
1316                                 printf( __( 'Use the current theme &mdash; %1$s &mdash; or <a href="%2$s">choose a new one</a>.' ), $theme->display('Name'), esc_url( admin_url( 'themes.php' ) ) );
1317                                 echo '</p>';
1318                         }
1319                 endif; ?>
1320         </div>
1321         </div>
1322         <p class="welcome-panel-dismiss"><?php printf( __( 'Already know what you&#8217;re doing? <a href="%s">Dismiss this message</a>.' ), esc_url( admin_url( '?welcome=0' ) ) ); ?></p>
1323         </div>
1324         </div>
1325         <?php
1326 }