home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-admin / includes / dashboard.php < prev    next >
Encoding:
PHP Script  |  2017-11-13  |  55.7 KB  |  1,622 lines

  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.  * @global array $wp_registered_widgets
  17.  * @global array $wp_registered_widget_controls
  18.  * @global array $wp_dashboard_control_callbacks
  19.  */
  20. function wp_dashboard_setup() {
  21.     global $wp_registered_widgets, $wp_registered_widget_controls, $wp_dashboard_control_callbacks;
  22.     $wp_dashboard_control_callbacks = array();
  23.     $screen = get_current_screen();
  24.  
  25.     /* Register Widgets and Controls */
  26.  
  27.     $response = wp_check_browser_version();
  28.  
  29.     if ( $response && $response['upgrade'] ) {
  30.         add_filter( 'postbox_classes_dashboard_dashboard_browser_nag', 'dashboard_browser_nag_class' );
  31.         if ( $response['insecure'] )
  32.             wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'You are using an insecure browser!' ), 'wp_dashboard_browser_nag' );
  33.         else
  34.             wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'Your browser is out of date!' ), 'wp_dashboard_browser_nag' );
  35.     }
  36.  
  37.     // Right Now
  38.     if ( is_blog_admin() && current_user_can('edit_posts') )
  39.         wp_add_dashboard_widget( 'dashboard_right_now', __( 'At a Glance' ), 'wp_dashboard_right_now' );
  40.  
  41.     if ( is_network_admin() )
  42.         wp_add_dashboard_widget( 'network_dashboard_right_now', __( 'Right Now' ), 'wp_network_dashboard_right_now' );
  43.  
  44.     // Activity Widget
  45.     if ( is_blog_admin() ) {
  46.         wp_add_dashboard_widget( 'dashboard_activity', __( 'Activity' ), 'wp_dashboard_site_activity' );
  47.     }
  48.  
  49.     // QuickPress Widget
  50.     if ( is_blog_admin() && current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) {
  51.         $quick_draft_title = sprintf( '<span class="hide-if-no-js">%1$s</span> <span class="hide-if-js">%2$s</span>', __( 'Quick Draft' ), __( 'Your Recent Drafts' ) );
  52.         wp_add_dashboard_widget( 'dashboard_quick_press', $quick_draft_title, 'wp_dashboard_quick_press' );
  53.     }
  54.  
  55.     // WordPress Events and News
  56.     wp_add_dashboard_widget( 'dashboard_primary', __( 'WordPress Events and News' ), 'wp_dashboard_events_news' );
  57.  
  58.     if ( is_network_admin() ) {
  59.  
  60.         /**
  61.          * Fires after core widgets for the Network Admin dashboard have been registered.
  62.          *
  63.          * @since 3.1.0
  64.          */
  65.         do_action( 'wp_network_dashboard_setup' );
  66.  
  67.         /**
  68.          * Filters the list of widgets to load for the Network Admin dashboard.
  69.          *
  70.          * @since 3.1.0
  71.          *
  72.          * @param array $dashboard_widgets An array of dashboard widgets.
  73.          */
  74.         $dashboard_widgets = apply_filters( 'wp_network_dashboard_widgets', array() );
  75.     } elseif ( is_user_admin() ) {
  76.  
  77.         /**
  78.          * Fires after core widgets for the User Admin dashboard have been registered.
  79.          *
  80.          * @since 3.1.0
  81.          */
  82.         do_action( 'wp_user_dashboard_setup' );
  83.  
  84.         /**
  85.          * Filters the list of widgets to load for the User Admin dashboard.
  86.          *
  87.          * @since 3.1.0
  88.          *
  89.          * @param array $dashboard_widgets An array of dashboard widgets.
  90.          */
  91.         $dashboard_widgets = apply_filters( 'wp_user_dashboard_widgets', array() );
  92.     } else {
  93.  
  94.         /**
  95.          * Fires after core widgets for the admin dashboard have been registered.
  96.          *
  97.          * @since 2.5.0
  98.          */
  99.         do_action( 'wp_dashboard_setup' );
  100.  
  101.         /**
  102.          * Filters the list of widgets to load for the admin dashboard.
  103.          *
  104.          * @since 2.5.0
  105.          *
  106.          * @param array $dashboard_widgets An array of dashboard widgets.
  107.          */
  108.         $dashboard_widgets = apply_filters( 'wp_dashboard_widgets', array() );
  109.     }
  110.  
  111.     foreach ( $dashboard_widgets as $widget_id ) {
  112.         $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>';
  113.         wp_add_dashboard_widget( $widget_id, $name, $wp_registered_widgets[$widget_id]['callback'], $wp_registered_widget_controls[$widget_id]['callback'] );
  114.     }
  115.  
  116.     if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget_id']) ) {
  117.         check_admin_referer( 'edit-dashboard-widget_' . $_POST['widget_id'], 'dashboard-widget-nonce' );
  118.         ob_start(); // hack - but the same hack wp-admin/widgets.php uses
  119.         wp_dashboard_trigger_widget_control( $_POST['widget_id'] );
  120.         ob_end_clean();
  121.         wp_redirect( remove_query_arg( 'edit' ) );
  122.         exit;
  123.     }
  124.  
  125.     /** This action is documented in wp-admin/edit-form-advanced.php */
  126.     do_action( 'do_meta_boxes', $screen->id, 'normal', '' );
  127.  
  128.     /** This action is documented in wp-admin/edit-form-advanced.php */
  129.     do_action( 'do_meta_boxes', $screen->id, 'side', '' );
  130. }
  131.  
  132. /**
  133.  * Adds a new dashboard widget.
  134.  *
  135.  * @since 2.7.0
  136.  *
  137.  * @global array $wp_dashboard_control_callbacks
  138.  *
  139.  * @param string   $widget_id        Widget ID  (used in the 'id' attribute for the widget).
  140.  * @param string   $widget_name      Title of the widget.
  141.  * @param callable $callback         Function that fills the widget with the desired content.
  142.  *                                   The function should echo its output.
  143.  * @param callable $control_callback Optional. Function that outputs controls for the widget. Default null.
  144.  * @param array    $callback_args    Optional. Data that should be set as the $args property of the widget array
  145.  *                                   (which is the second parameter passed to your callback). Default null.
  146.  */
  147. function wp_add_dashboard_widget( $widget_id, $widget_name, $callback, $control_callback = null, $callback_args = null ) {
  148.     $screen = get_current_screen();
  149.     global $wp_dashboard_control_callbacks;
  150.  
  151.     $private_callback_args = array( '__widget_basename' => $widget_name );
  152.  
  153.     if ( is_null( $callback_args ) ) {
  154.         $callback_args = $private_callback_args;
  155.     } else if ( is_array( $callback_args ) ) {
  156.         $callback_args = array_merge( $callback_args, $private_callback_args );
  157.     }
  158.  
  159.     if ( $control_callback && current_user_can( 'edit_dashboard' ) && is_callable( $control_callback ) ) {
  160.         $wp_dashboard_control_callbacks[$widget_id] = $control_callback;
  161.         if ( isset( $_GET['edit'] ) && $widget_id == $_GET['edit'] ) {
  162.             list($url) = explode( '#', add_query_arg( 'edit', false ), 2 );
  163.             $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( $url ) . '">' . __( 'Cancel' ) . '</a></span>';
  164.             $callback = '_wp_dashboard_control_callback';
  165.         } else {
  166.             list($url) = explode( '#', add_query_arg( 'edit', $widget_id ), 2 );
  167.             $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( "$url#$widget_id" ) . '" class="edit-box open-box">' . __( 'Configure' ) . '</a></span>';
  168.         }
  169.     }
  170.  
  171.     $side_widgets = array( 'dashboard_quick_press', 'dashboard_primary' );
  172.  
  173.     $location = 'normal';
  174.     if ( in_array($widget_id, $side_widgets) )
  175.         $location = 'side';
  176.  
  177.     $priority = 'core';
  178.     if ( 'dashboard_browser_nag' === $widget_id )
  179.         $priority = 'high';
  180.  
  181.     add_meta_box( $widget_id, $widget_name, $callback, $screen, $location, $priority, $callback_args );
  182. }
  183.  
  184. /**
  185.  * Outputs controls for the current dashboard widget.
  186.  *
  187.  * @access private
  188.  * @since 2.7.0
  189.  *
  190.  * @param mixed $dashboard
  191.  * @param array $meta_box
  192.  */
  193. function _wp_dashboard_control_callback( $dashboard, $meta_box ) {
  194.     echo '<form method="post" class="dashboard-widget-control-form wp-clearfix">';
  195.     wp_dashboard_trigger_widget_control( $meta_box['id'] );
  196.     wp_nonce_field( 'edit-dashboard-widget_' . $meta_box['id'], 'dashboard-widget-nonce' );
  197.     echo '<input type="hidden" name="widget_id" value="' . esc_attr($meta_box['id']) . '" />';
  198.     submit_button( __('Submit') );
  199.     echo '</form>';
  200. }
  201.  
  202. /**
  203.  * Displays the dashboard.
  204.  *
  205.  * @since 2.5.0
  206.  */
  207. function wp_dashboard() {
  208.     $screen = get_current_screen();
  209.     $columns = absint( $screen->get_columns() );
  210.     $columns_css = '';
  211.     if ( $columns ) {
  212.         $columns_css = " columns-$columns";
  213.     }
  214.  
  215. ?>
  216. <div id="dashboard-widgets" class="metabox-holder<?php echo $columns_css; ?>">
  217.     <div id="postbox-container-1" class="postbox-container">
  218.     <?php do_meta_boxes( $screen->id, 'normal', '' ); ?>
  219.     </div>
  220.     <div id="postbox-container-2" class="postbox-container">
  221.     <?php do_meta_boxes( $screen->id, 'side', '' ); ?>
  222.     </div>
  223.     <div id="postbox-container-3" class="postbox-container">
  224.     <?php do_meta_boxes( $screen->id, 'column3', '' ); ?>
  225.     </div>
  226.     <div id="postbox-container-4" class="postbox-container">
  227.     <?php do_meta_boxes( $screen->id, 'column4', '' ); ?>
  228.     </div>
  229. </div>
  230.  
  231. <?php
  232.     wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
  233.     wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
  234.  
  235. }
  236.  
  237. //
  238. // Dashboard Widgets
  239. //
  240.  
  241. /**
  242.  * Dashboard widget that displays some basic stats about the site.
  243.  *
  244.  * Formerly 'Right Now'. A streamlined 'At a Glance' as of 3.8.
  245.  *
  246.  * @since 2.7.0
  247.  */
  248. function wp_dashboard_right_now() {
  249. ?>
  250.     <div class="main">
  251.     <ul>
  252.     <?php
  253.     // Posts and Pages
  254.     foreach ( array( 'post', 'page' ) as $post_type ) {
  255.         $num_posts = wp_count_posts( $post_type );
  256.         if ( $num_posts && $num_posts->publish ) {
  257.             if ( 'post' == $post_type ) {
  258.                 $text = _n( '%s Post', '%s Posts', $num_posts->publish );
  259.             } else {
  260.                 $text = _n( '%s Page', '%s Pages', $num_posts->publish );
  261.             }
  262.             $text = sprintf( $text, number_format_i18n( $num_posts->publish ) );
  263.             $post_type_object = get_post_type_object( $post_type );
  264.             if ( $post_type_object && current_user_can( $post_type_object->cap->edit_posts ) ) {
  265.                 printf( '<li class="%1$s-count"><a href="edit.php?post_type=%1$s">%2$s</a></li>', $post_type, $text );
  266.             } else {
  267.                 printf( '<li class="%1$s-count"><span>%2$s</span></li>', $post_type, $text );
  268.             }
  269.  
  270.         }
  271.     }
  272.     // Comments
  273.     $num_comm = wp_count_comments();
  274.     if ( $num_comm && ( $num_comm->approved || $num_comm->moderated ) ) {
  275.         $text = sprintf( _n( '%s Comment', '%s Comments', $num_comm->approved ), number_format_i18n( $num_comm->approved ) );
  276.         ?>
  277.         <li class="comment-count"><a href="edit-comments.php"><?php echo $text; ?></a></li>
  278.         <?php
  279.         $moderated_comments_count_i18n = number_format_i18n( $num_comm->moderated );
  280.         /* translators: %s: number of comments in moderation */
  281.         $text = sprintf( _nx( '%s in moderation', '%s in moderation', $num_comm->moderated, 'comments' ), $moderated_comments_count_i18n );
  282.         /* translators: %s: number of comments in moderation */
  283.         $aria_label = sprintf( _nx( '%s comment in moderation', '%s comments in moderation', $num_comm->moderated, 'comments' ), $moderated_comments_count_i18n );
  284.         ?>
  285.         <li class="comment-mod-count<?php
  286.             if ( ! $num_comm->moderated ) {
  287.                 echo ' hidden';
  288.             }
  289.         ?>"><a href="edit-comments.php?comment_status=moderated" aria-label="<?php esc_attr_e( $aria_label ); ?>"><?php echo $text; ?></a></li>
  290.         <?php
  291.     }
  292.  
  293.     /**
  294.      * Filters the array of extra elements to list in the 'At a Glance'
  295.      * dashboard widget.
  296.      *
  297.      * Prior to 3.8.0, the widget was named 'Right Now'. Each element
  298.      * is wrapped in list-item tags on output.
  299.      *
  300.      * @since 3.8.0
  301.      *
  302.      * @param array $items Array of extra 'At a Glance' widget items.
  303.      */
  304.     $elements = apply_filters( 'dashboard_glance_items', array() );
  305.  
  306.     if ( $elements ) {
  307.         echo '<li>' . implode( "</li>\n<li>", $elements ) . "</li>\n";
  308.     }
  309.  
  310.     ?>
  311.     </ul>
  312.     <?php
  313.     update_right_now_message();
  314.  
  315.     // Check if search engines are asked not to index this site.
  316.     if ( ! is_network_admin() && ! is_user_admin() && current_user_can( 'manage_options' ) && '0' == get_option( 'blog_public' ) ) {
  317.  
  318.         /**
  319.          * Filters the link title attribute for the 'Search Engines Discouraged'
  320.          * message displayed in the 'At a Glance' dashboard widget.
  321.          *
  322.          * Prior to 3.8.0, the widget was named 'Right Now'.
  323.          *
  324.          * @since 3.0.0
  325.          * @since 4.5.0 The default for `$title` was updated to an empty string.
  326.          *
  327.          * @param string $title Default attribute text.
  328.          */
  329.         $title = apply_filters( 'privacy_on_link_title', '' );
  330.  
  331.         /**
  332.          * Filters the link label for the 'Search Engines Discouraged' message
  333.          * displayed in the 'At a Glance' dashboard widget.
  334.          *
  335.          * Prior to 3.8.0, the widget was named 'Right Now'.
  336.          *
  337.          * @since 3.0.0
  338.          *
  339.          * @param string $content Default text.
  340.          */
  341.         $content = apply_filters( 'privacy_on_link_text' , __( 'Search Engines Discouraged' ) );
  342.         $title_attr = '' === $title ? '' : " title='$title'";
  343.  
  344.         echo "<p><a href='options-reading.php'$title_attr>$content</a></p>";
  345.     }
  346.     ?>
  347.     </div>
  348.     <?php
  349.     /*
  350.      * activity_box_end has a core action, but only prints content when multisite.
  351.      * Using an output buffer is the only way to really check if anything's displayed here.
  352.      */
  353.     ob_start();
  354.  
  355.     /**
  356.      * Fires at the end of the 'At a Glance' dashboard widget.
  357.      *
  358.      * Prior to 3.8.0, the widget was named 'Right Now'.
  359.      *
  360.      * @since 2.5.0
  361.      */
  362.     do_action( 'rightnow_end' );
  363.  
  364.     /**
  365.      * Fires at the end of the 'At a Glance' dashboard widget.
  366.      *
  367.      * Prior to 3.8.0, the widget was named 'Right Now'.
  368.      *
  369.      * @since 2.0.0
  370.      */
  371.     do_action( 'activity_box_end' );
  372.  
  373.     $actions = ob_get_clean();
  374.  
  375.     if ( !empty( $actions ) ) : ?>
  376.     <div class="sub">
  377.         <?php echo $actions; ?>
  378.     </div>
  379.     <?php endif;
  380. }
  381.  
  382. /**
  383.  * @since 3.1.0
  384.  */
  385. function wp_network_dashboard_right_now() {
  386.     $actions = array();
  387.     if ( current_user_can('create_sites') )
  388.         $actions['create-site'] = '<a href="' . network_admin_url('site-new.php') . '">' . __( 'Create a New Site' ) . '</a>';
  389.     if ( current_user_can('create_users') )
  390.         $actions['create-user'] = '<a href="' . network_admin_url('user-new.php') . '">' . __( 'Create a New User' ) . '</a>';
  391.  
  392.     $c_users = get_user_count();
  393.     $c_blogs = get_blog_count();
  394.  
  395.     /* translators: %s: number of users on the network */
  396.     $user_text = sprintf( _n( '%s user', '%s users', $c_users ), number_format_i18n( $c_users ) );
  397.     /* translators: %s: number of sites on the network */
  398.     $blog_text = sprintf( _n( '%s site', '%s sites', $c_blogs ), number_format_i18n( $c_blogs ) );
  399.  
  400.     /* translators: 1: text indicating the number of sites on the network, 2: text indicating the number of users on the network */
  401.     $sentence = sprintf( __( 'You have %1$s and %2$s.' ), $blog_text, $user_text );
  402.  
  403.     if ( $actions ) {
  404.         echo '<ul class="subsubsub">';
  405.         foreach ( $actions as $class => $action ) {
  406.              $actions[ $class ] = "\t<li class='$class'>$action";
  407.         }
  408.         echo implode( " |</li>\n", $actions ) . "</li>\n";
  409.         echo '</ul>';
  410.     }
  411. ?>
  412.     <br class="clear" />
  413.  
  414.     <p class="youhave"><?php echo $sentence; ?></p>
  415.  
  416.  
  417.     <?php
  418.         /**
  419.          * Fires in the Network Admin 'Right Now' dashboard widget
  420.          * just before the user and site search form fields.
  421.          *
  422.          * @since MU (3.0.0)
  423.          *
  424.          * @param null $unused
  425.          */
  426.         do_action( 'wpmuadminresult', '' );
  427.     ?>
  428.  
  429.     <form action="<?php echo network_admin_url('users.php'); ?>" method="get">
  430.         <p>
  431.             <label class="screen-reader-text" for="search-users"><?php _e( 'Search Users' ); ?></label>
  432.             <input type="search" name="s" value="" size="30" autocomplete="off" id="search-users"/>
  433.             <?php submit_button( __( 'Search Users' ), '', false, false, array( 'id' => 'submit_users' ) ); ?>
  434.         </p>
  435.     </form>
  436.  
  437.     <form action="<?php echo network_admin_url('sites.php'); ?>" method="get">
  438.         <p>
  439.             <label class="screen-reader-text" for="search-sites"><?php _e( 'Search Sites' ); ?></label>
  440.             <input type="search" name="s" value="" size="30" autocomplete="off" id="search-sites"/>
  441.             <?php submit_button( __( 'Search Sites' ), '', false, false, array( 'id' => 'submit_sites' ) ); ?>
  442.         </p>
  443.     </form>
  444. <?php
  445.     /**
  446.      * Fires at the end of the 'Right Now' widget in the Network Admin dashboard.
  447.      *
  448.      * @since MU (3.0.0)
  449.      */
  450.     do_action( 'mu_rightnow_end' );
  451.  
  452.     /**
  453.      * Fires at the end of the 'Right Now' widget in the Network Admin dashboard.
  454.      *
  455.      * @since MU (3.0.0)
  456.      */
  457.     do_action( 'mu_activity_box_end' );
  458. }
  459.  
  460. /**
  461.  * The Quick Draft widget display and creation of drafts.
  462.  *
  463.  * @since 3.8.0
  464.  *
  465.  * @global int $post_ID
  466.  *
  467.  * @param string $error_msg Optional. Error message. Default false.
  468.  */
  469. function wp_dashboard_quick_press( $error_msg = false ) {
  470.     global $post_ID;
  471.  
  472.     if ( ! current_user_can( 'edit_posts' ) ) {
  473.         return;
  474.     }
  475.  
  476.     /* Check if a new auto-draft (= no new post_ID) is needed or if the old can be used */
  477.     $last_post_id = (int) get_user_option( 'dashboard_quick_press_last_post_id' ); // Get the last post_ID
  478.     if ( $last_post_id ) {
  479.         $post = get_post( $last_post_id );
  480.         if ( empty( $post ) || $post->post_status != 'auto-draft' ) { // auto-draft doesn't exists anymore
  481.             $post = get_default_post_to_edit( 'post', true );
  482.             update_user_option( get_current_user_id(), 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID
  483.         } else {
  484.             $post->post_title = ''; // Remove the auto draft title
  485.         }
  486.     } else {
  487.         $post = get_default_post_to_edit( 'post' , true);
  488.         $user_id = get_current_user_id();
  489.         // Don't create an option if this is a super admin who does not belong to this site.
  490.         if ( in_array( get_current_blog_id(), array_keys( get_blogs_of_user( $user_id ) ) ) )
  491.             update_user_option( $user_id, 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID
  492.     }
  493.  
  494.     $post_ID = (int) $post->ID;
  495. ?>
  496.  
  497.     <form name="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>" method="post" id="quick-press" class="initial-form hide-if-no-js">
  498.  
  499.         <?php if ( $error_msg ) : ?>
  500.         <div class="error"><?php echo $error_msg; ?></div>
  501.         <?php endif; ?>
  502.  
  503.         <div class="input-text-wrap" id="title-wrap">
  504.             <label class="screen-reader-text prompt" for="title" id="title-prompt-text">
  505.  
  506.                 <?php
  507.                 /** This filter is documented in wp-admin/edit-form-advanced.php */
  508.                 echo apply_filters( 'enter_title_here', __( 'Title' ), $post );
  509.                 ?>
  510.             </label>
  511.             <input type="text" name="post_title" id="title" autocomplete="off" />
  512.         </div>
  513.  
  514.         <div class="textarea-wrap" id="description-wrap">
  515.             <label class="screen-reader-text prompt" for="content" id="content-prompt-text"><?php _e( 'What’s on your mind?' ); ?></label>
  516.             <textarea name="content" id="content" class="mceEditor" rows="3" cols="15" autocomplete="off"></textarea>
  517.         </div>
  518.  
  519.         <p class="submit">
  520.             <input type="hidden" name="action" id="quickpost-action" value="post-quickdraft-save" />
  521.             <input type="hidden" name="post_ID" value="<?php echo $post_ID; ?>" />
  522.             <input type="hidden" name="post_type" value="post" />
  523.             <?php wp_nonce_field( 'add-post' ); ?>
  524.             <?php submit_button( __( 'Save Draft' ), 'primary', 'save', false, array( 'id' => 'save-post' ) ); ?>
  525.             <br class="clear" />
  526.         </p>
  527.  
  528.     </form>
  529.     <?php
  530.     wp_dashboard_recent_drafts();
  531. }
  532.  
  533. /**
  534.  * Show recent drafts of the user on the dashboard.
  535.  *
  536.  * @since 2.7.0
  537.  *
  538.  * @param array $drafts
  539.  */
  540. function wp_dashboard_recent_drafts( $drafts = false ) {
  541.     if ( ! $drafts ) {
  542.         $query_args = array(
  543.             'post_type'      => 'post',
  544.             'post_status'    => 'draft',
  545.             'author'         => get_current_user_id(),
  546.             'posts_per_page' => 4,
  547.             'orderby'        => 'modified',
  548.             'order'          => 'DESC'
  549.         );
  550.  
  551.         /**
  552.          * Filters the post query arguments for the 'Recent Drafts' dashboard widget.
  553.          *
  554.          * @since 4.4.0
  555.          *
  556.          * @param array $query_args The query arguments for the 'Recent Drafts' dashboard widget.
  557.          */
  558.         $query_args = apply_filters( 'dashboard_recent_drafts_query_args', $query_args );
  559.  
  560.         $drafts = get_posts( $query_args );
  561.         if ( ! $drafts ) {
  562.             return;
  563.          }
  564.      }
  565.  
  566.     echo '<div class="drafts">';
  567.     if ( count( $drafts ) > 3 ) {
  568.         echo '<p class="view-all"><a href="' . esc_url( admin_url( 'edit.php?post_status=draft' ) ) . '">' . __( 'View all drafts' ) . "</a></p>\n";
  569.      }
  570.     echo '<h2 class="hide-if-no-js">' . __( 'Your Recent Drafts' ) . "</h2>\n<ul>";
  571.  
  572.     $drafts = array_slice( $drafts, 0, 3 );
  573.     foreach ( $drafts as $draft ) {
  574.         $url = get_edit_post_link( $draft->ID );
  575.         $title = _draft_or_post_title( $draft->ID );
  576.         echo "<li>\n";
  577.         /* translators: %s: post title */
  578.         echo '<div class="draft-title"><a href="' . esc_url( $url ) . '" aria-label="' . esc_attr( sprintf( __( 'Edit “%s”' ), $title ) ) . '">' . esc_html( $title ) . '</a>';
  579.         echo '<time datetime="' . get_the_time( 'c', $draft ) . '">' . get_the_time( __( 'F j, Y' ), $draft ) . '</time></div>';
  580.         if ( $the_content = wp_trim_words( $draft->post_content, 10 ) ) {
  581.             echo '<p>' . $the_content . '</p>';
  582.          }
  583.         echo "</li>\n";
  584.      }
  585.     echo "</ul>\n</div>";
  586. }
  587.  
  588. /**
  589.  * Outputs a row for the Recent Comments widget.
  590.  *
  591.  * @access private
  592.  * @since 2.7.0
  593.  *
  594.  * @global WP_Comment $comment
  595.  *
  596.  * @param WP_Comment $comment   The current comment.
  597.  * @param bool       $show_date Optional. Whether to display the date.
  598.  */
  599. function _wp_dashboard_recent_comments_row( &$comment, $show_date = true ) {
  600.     $GLOBALS['comment'] = clone $comment;
  601.  
  602.     if ( $comment->comment_post_ID > 0 ) {
  603.  
  604.         $comment_post_title = _draft_or_post_title( $comment->comment_post_ID );
  605.         $comment_post_url = get_the_permalink( $comment->comment_post_ID );
  606.         $comment_post_link = "<a href='$comment_post_url'>$comment_post_title</a>";
  607.     } else {
  608.         $comment_post_link = '';
  609.     }
  610.  
  611.     $actions_string = '';
  612.     if ( current_user_can( 'edit_comment', $comment->comment_ID ) ) {
  613.         // Pre-order it: Approve | Reply | Edit | Spam | Trash.
  614.         $actions = array(
  615.             'approve' => '', 'unapprove' => '',
  616.             'reply' => '',
  617.             'edit' => '',
  618.             'spam' => '',
  619.             'trash' => '', 'delete' => '',
  620.             'view' => '',
  621.         );
  622.  
  623.         $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
  624.         $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
  625.  
  626.         $approve_url = esc_url( "comment.php?action=approvecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$approve_nonce" );
  627.         $unapprove_url = esc_url( "comment.php?action=unapprovecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$approve_nonce" );
  628.         $spam_url = esc_url( "comment.php?action=spamcomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
  629.         $trash_url = esc_url( "comment.php?action=trashcomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
  630.         $delete_url = esc_url( "comment.php?action=deletecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
  631.  
  632.         $actions['approve'] = "<a href='$approve_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved' class='vim-a' aria-label='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
  633.         $actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved' class='vim-u' aria-label='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
  634.         $actions['edit'] = "<a href='comment.php?action=editcomment&c={$comment->comment_ID}' aria-label='" . esc_attr__( 'Edit this comment' ) . "'>". __( 'Edit' ) . '</a>';
  635.         $actions['reply'] = '<a onclick="window.commentReply && commentReply.open(\'' . $comment->comment_ID . '\',\''.$comment->comment_post_ID.'\');return false;" class="vim-r hide-if-no-js" aria-label="' . esc_attr__( 'Reply to this comment' ) . '" href="#">' . __( 'Reply' ) . '</a>';
  636.         $actions['spam'] = "<a href='$spam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::spam=1' class='vim-s vim-destructive' aria-label='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
  637.  
  638.         if ( ! EMPTY_TRASH_DAYS ) {
  639.             $actions['delete'] = "<a href='$delete_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' aria-label='" . esc_attr__( 'Delete this comment permanently' ) . "'>" . __( 'Delete Permanently' ) . '</a>';
  640.         } else {
  641.             $actions['trash'] = "<a href='$trash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' aria-label='" . esc_attr__( 'Move this comment to the Trash' ) . "'>" . _x( 'Trash', 'verb' ) . '</a>';
  642.         }
  643.  
  644.         $actions['view'] = '<a class="comment-link" href="' . esc_url( get_comment_link( $comment ) ) . '" aria-label="' . esc_attr__( 'View this comment' ) . '">' . __( 'View' ) . '</a>';
  645.  
  646.         /**
  647.          * Filters the action links displayed for each comment in the 'Recent Comments'
  648.          * dashboard widget.
  649.          *
  650.          * @since 2.6.0
  651.          *
  652.          * @param array      $actions An array of comment actions. Default actions include:
  653.          *                            'Approve', 'Unapprove', 'Edit', 'Reply', 'Spam',
  654.          *                            'Delete', and 'Trash'.
  655.          * @param WP_Comment $comment The comment object.
  656.          */
  657.         $actions = apply_filters( 'comment_row_actions', array_filter($actions), $comment );
  658.  
  659.         $i = 0;
  660.         foreach ( $actions as $action => $link ) {
  661.             ++$i;
  662.             ( ( ('approve' == $action || 'unapprove' == $action) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
  663.  
  664.             // Reply and quickedit need a hide-if-no-js span
  665.             if ( 'reply' == $action || 'quickedit' == $action ) {
  666.                 $action .= ' hide-if-no-js';
  667.             }
  668.  
  669.             if ( 'view' === $action && '1' !== $comment->comment_approved ) {
  670.                 $action .= ' hidden';
  671.             }
  672.             $actions_string .= "<span class='$action'>$sep$link</span>";
  673.         }
  674.     }
  675. ?>
  676.  
  677.         <li id="comment-<?php echo $comment->comment_ID; ?>" <?php comment_class( array( 'comment-item', wp_get_comment_status( $comment ) ), $comment ); ?>>
  678.  
  679.             <?php echo get_avatar( $comment, 50, 'mystery' ); ?>
  680.  
  681.             <?php if ( !$comment->comment_type || 'comment' == $comment->comment_type ) : ?>
  682.  
  683.             <div class="dashboard-comment-wrap has-row-actions">
  684.             <p class="comment-meta">
  685.             <?php
  686.                 // Comments might not have a post they relate to, e.g. programmatically created ones.
  687.                 if ( $comment_post_link ) {
  688.                     printf(
  689.                         /* translators: 1: comment author, 2: post link, 3: notification if the comment is pending */
  690.                         __( 'From %1$s on %2$s %3$s' ),
  691.                         '<cite class="comment-author">' . get_comment_author_link( $comment ) . '</cite>',
  692.                         $comment_post_link,
  693.                         '<span class="approve">' . __( '[Pending]' ) . '</span>'
  694.                     );
  695.                 } else {
  696.                     printf(
  697.                         /* translators: 1: comment author, 2: notification if the comment is pending */
  698.                         __( 'From %1$s %2$s' ),
  699.                         '<cite class="comment-author">' . get_comment_author_link( $comment ) . '</cite>',
  700.                         '<span class="approve">' . __( '[Pending]' ) . '</span>'
  701.                     );
  702.                 }
  703.             ?>
  704.             </p>
  705.  
  706.             <?php
  707.             else :
  708.                 switch ( $comment->comment_type ) {
  709.                     case 'pingback' :
  710.                         $type = __( 'Pingback' );
  711.                         break;
  712.                     case 'trackback' :
  713.                         $type = __( 'Trackback' );
  714.                         break;
  715.                     default :
  716.                         $type = ucwords( $comment->comment_type );
  717.                 }
  718.                 $type = esc_html( $type );
  719.             ?>
  720.             <div class="dashboard-comment-wrap has-row-actions">
  721.             <p class="comment-meta">
  722.             <?php
  723.                 // Pingbacks, Trackbacks or custom comment types might not have a post they relate to, e.g. programmatically created ones.
  724.                 if ( $comment_post_link ) {
  725.                     printf(
  726.                         /* translators: 1: type of comment, 2: post link, 3: notification if the comment is pending */
  727.                         _x( '%1$s on %2$s %3$s', 'dashboard' ),
  728.                         "<strong>$type</strong>",
  729.                         $comment_post_link,
  730.                         '<span class="approve">' . __( '[Pending]' ) . '</span>'
  731.                     );
  732.                 } else {
  733.                     printf(
  734.                         /* translators: 1: type of comment, 2: notification if the comment is pending */
  735.                         _x( '%1$s %2$s', 'dashboard' ),
  736.                         "<strong>$type</strong>",
  737.                         '<span class="approve">' . __( '[Pending]' ) . '</span>'
  738.                     );
  739.                 }
  740.             ?>
  741.             </p>
  742.             <p class="comment-author"><?php comment_author_link( $comment ); ?></p>
  743.  
  744.             <?php endif; // comment_type ?>
  745.             <blockquote><p><?php comment_excerpt( $comment ); ?></p></blockquote>
  746.             <?php if ( $actions_string ) : ?>
  747.             <p class="row-actions"><?php echo $actions_string; ?></p>
  748.             <?php endif; ?>
  749.             </div>
  750.         </li>
  751. <?php
  752.     $GLOBALS['comment'] = null;
  753. }
  754.  
  755. /**
  756.  * Callback function for Activity widget.
  757.  *
  758.  * @since 3.8.0
  759.  */
  760. function wp_dashboard_site_activity() {
  761.  
  762.     echo '<div id="activity-widget">';
  763.  
  764.     $future_posts = wp_dashboard_recent_posts( array(
  765.         'max'     => 5,
  766.         'status'  => 'future',
  767.         'order'   => 'ASC',
  768.         'title'   => __( 'Publishing Soon' ),
  769.         'id'      => 'future-posts',
  770.     ) );
  771.     $recent_posts = wp_dashboard_recent_posts( array(
  772.         'max'     => 5,
  773.         'status'  => 'publish',
  774.         'order'   => 'DESC',
  775.         'title'   => __( 'Recently Published' ),
  776.         'id'      => 'published-posts',
  777.     ) );
  778.  
  779.     $recent_comments = wp_dashboard_recent_comments();
  780.  
  781.     if ( !$future_posts && !$recent_posts && !$recent_comments ) {
  782.         echo '<div class="no-activity">';
  783.         echo '<p class="smiley" aria-hidden="true"></p>';
  784.         echo '<p>' . __( 'No activity yet!' ) . '</p>';
  785.         echo '</div>';
  786.     }
  787.  
  788.     echo '</div>';
  789. }
  790.  
  791. /**
  792.  * Generates Publishing Soon and Recently Published sections.
  793.  *
  794.  * @since 3.8.0
  795.  *
  796.  * @param array $args {
  797.  *     An array of query and display arguments.
  798.  *
  799.  *     @type int    $max     Number of posts to display.
  800.  *     @type string $status  Post status.
  801.  *     @type string $order   Designates ascending ('ASC') or descending ('DESC') order.
  802.  *     @type string $title   Section title.
  803.  *     @type string $id      The container id.
  804.  * }
  805.  * @return bool False if no posts were found. True otherwise.
  806.  */
  807. function wp_dashboard_recent_posts( $args ) {
  808.     $query_args = array(
  809.         'post_type'      => 'post',
  810.         'post_status'    => $args['status'],
  811.         'orderby'        => 'date',
  812.         'order'          => $args['order'],
  813.         'posts_per_page' => intval( $args['max'] ),
  814.         'no_found_rows'  => true,
  815.         'cache_results'  => false,
  816.         'perm'           => ( 'future' === $args['status'] ) ? 'editable' : 'readable',
  817.     );
  818.  
  819.     /**
  820.      * Filters the query arguments used for the Recent Posts widget.
  821.      *
  822.      * @since 4.2.0
  823.      *
  824.      * @param array $query_args The arguments passed to WP_Query to produce the list of posts.
  825.      */
  826.     $query_args = apply_filters( 'dashboard_recent_posts_query_args', $query_args );
  827.     $posts = new WP_Query( $query_args );
  828.  
  829.     if ( $posts->have_posts() ) {
  830.  
  831.         echo '<div id="' . $args['id'] . '" class="activity-block">';
  832.  
  833.         echo '<h3>' . $args['title'] . '</h3>';
  834.  
  835.         echo '<ul>';
  836.  
  837.         $today    = date( 'Y-m-d', current_time( 'timestamp' ) );
  838.         $tomorrow = date( 'Y-m-d', strtotime( '+1 day', current_time( 'timestamp' ) ) );
  839.  
  840.         while ( $posts->have_posts() ) {
  841.             $posts->the_post();
  842.  
  843.             $time = get_the_time( 'U' );
  844.             if ( date( 'Y-m-d', $time ) == $today ) {
  845.                 $relative = __( 'Today' );
  846.             } elseif ( date( 'Y-m-d', $time ) == $tomorrow ) {
  847.                 $relative = __( 'Tomorrow' );
  848.             } elseif ( date( 'Y', $time ) !== date( 'Y', current_time( 'timestamp' ) ) ) {
  849.                 /* translators: date and time format for recent posts on the dashboard, from a different calendar year, see https://secure.php.net/date */
  850.                 $relative = date_i18n( __( 'M jS Y' ), $time );
  851.             } else {
  852.                 /* translators: date and time format for recent posts on the dashboard, see https://secure.php.net/date */
  853.                 $relative = date_i18n( __( 'M jS' ), $time );
  854.             }
  855.  
  856.             // Use the post edit link for those who can edit, the permalink otherwise.
  857.             $recent_post_link = current_user_can( 'edit_post', get_the_ID() ) ? get_edit_post_link() : get_permalink();
  858.  
  859.             $draft_or_post_title = _draft_or_post_title();
  860.             printf(
  861.                 '<li><span>%1$s</span> <a href="%2$s" aria-label="%3$s">%4$s</a></li>',
  862.                 /* translators: 1: relative date, 2: time */
  863.                 sprintf( _x( '%1$s, %2$s', 'dashboard' ), $relative, get_the_time() ),
  864.                 $recent_post_link,
  865.                 /* translators: %s: post title */
  866.                 esc_attr( sprintf( __( 'Edit “%s”' ), $draft_or_post_title ) ),
  867.                 $draft_or_post_title
  868.             );
  869.         }
  870.  
  871.         echo '</ul>';
  872.         echo '</div>';
  873.  
  874.     } else {
  875.         return false;
  876.     }
  877.  
  878.     wp_reset_postdata();
  879.  
  880.     return true;
  881. }
  882.  
  883. /**
  884.  * Show Comments section.
  885.  *
  886.  * @since 3.8.0
  887.  *
  888.  * @param int $total_items Optional. Number of comments to query. Default 5.
  889.  * @return bool False if no comments were found. True otherwise.
  890.  */
  891. function wp_dashboard_recent_comments( $total_items = 5 ) {
  892.     // Select all comment types and filter out spam later for better query performance.
  893.     $comments = array();
  894.  
  895.     $comments_query = array(
  896.         'number' => $total_items * 5,
  897.         'offset' => 0
  898.     );
  899.     if ( ! current_user_can( 'edit_posts' ) )
  900.         $comments_query['status'] = 'approve';
  901.  
  902.     while ( count( $comments ) < $total_items && $possible = get_comments( $comments_query ) ) {
  903.         if ( ! is_array( $possible ) ) {
  904.             break;
  905.         }
  906.         foreach ( $possible as $comment ) {
  907.             if ( ! current_user_can( 'read_post', $comment->comment_post_ID ) )
  908.                 continue;
  909.             $comments[] = $comment;
  910.             if ( count( $comments ) == $total_items )
  911.                 break 2;
  912.         }
  913.         $comments_query['offset'] += $comments_query['number'];
  914.         $comments_query['number'] = $total_items * 10;
  915.     }
  916.  
  917.     if ( $comments ) {
  918.         echo '<div id="latest-comments" class="activity-block">';
  919.         echo '<h3>' . __( 'Recent Comments' ) . '</h3>';
  920.  
  921.         echo '<ul id="the-comment-list" data-wp-lists="list:comment">';
  922.         foreach ( $comments as $comment )
  923.             _wp_dashboard_recent_comments_row( $comment );
  924.         echo '</ul>';
  925.  
  926.         if ( current_user_can( 'edit_posts' ) ) {
  927.             echo '<h3 class="screen-reader-text">' . __( 'View more comments' ) . '</h3>';
  928.             _get_list_table( 'WP_Comments_List_Table' )->views();
  929.         }
  930.  
  931.         wp_comment_reply( -1, false, 'dashboard', false );
  932.         wp_comment_trashnotice();
  933.  
  934.         echo '</div>';
  935.     } else {
  936.         return false;
  937.     }
  938.     return true;
  939. }
  940.  
  941. /**
  942.  * Display generic dashboard RSS widget feed.
  943.  *
  944.  * @since 2.5.0
  945.  *
  946.  * @param string $widget_id
  947.  */
  948. function wp_dashboard_rss_output( $widget_id ) {
  949.     $widgets = get_option( 'dashboard_widget_options' );
  950.     echo '<div class="rss-widget">';
  951.     wp_widget_rss_output( $widgets[ $widget_id ] );
  952.     echo "</div>";
  953. }
  954.  
  955. /**
  956.  * Checks to see if all of the feed url in $check_urls are cached.
  957.  *
  958.  * If $check_urls is empty, look for the rss feed url found in the dashboard
  959.  * widget options of $widget_id. If cached, call $callback, a function that
  960.  * echoes out output for this widget. If not cache, echo a "Loading..." stub
  961.  * which is later replaced by Ajax call (see top of /wp-admin/index.php)
  962.  *
  963.  * @since 2.5.0
  964.  *
  965.  * @param string $widget_id
  966.  * @param callable $callback
  967.  * @param array $check_urls RSS feeds
  968.  * @return bool False on failure. True on success.
  969.  */
  970. function wp_dashboard_cached_rss_widget( $widget_id, $callback, $check_urls = array() ) {
  971.     $loading = '<p class="widget-loading hide-if-no-js">' . __( 'Loading…' ) . '</p><div class="hide-if-js notice notice-error inline"><p>' . __( 'This widget requires JavaScript.' ) . '</p></div>';
  972.     $doing_ajax = wp_doing_ajax();
  973.  
  974.     if ( empty($check_urls) ) {
  975.         $widgets = get_option( 'dashboard_widget_options' );
  976.         if ( empty($widgets[$widget_id]['url']) && ! $doing_ajax ) {
  977.             echo $loading;
  978.             return false;
  979.         }
  980.         $check_urls = array( $widgets[$widget_id]['url'] );
  981.     }
  982.  
  983.     $locale = get_user_locale();
  984.     $cache_key = 'dash_v2_' . md5( $widget_id . '_' . $locale );
  985.     if ( false !== ( $output = get_transient( $cache_key ) ) ) {
  986.         echo $output;
  987.         return true;
  988.     }
  989.  
  990.     if ( ! $doing_ajax ) {
  991.         echo $loading;
  992.         return false;
  993.     }
  994.  
  995.     if ( $callback && is_callable( $callback ) ) {
  996.         $args = array_slice( func_get_args(), 3 );
  997.         array_unshift( $args, $widget_id, $check_urls );
  998.         ob_start();
  999.         call_user_func_array( $callback, $args );
  1000.         set_transient( $cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS ); // Default lifetime in cache of 12 hours (same as the feeds)
  1001.     }
  1002.  
  1003.     return true;
  1004. }
  1005.  
  1006. //
  1007. // Dashboard Widgets Controls
  1008. //
  1009.  
  1010. /**
  1011.  * Calls widget control callback.
  1012.  *
  1013.  * @since 2.5.0
  1014.  *
  1015.  * @global array $wp_dashboard_control_callbacks
  1016.  *
  1017.  * @param int $widget_control_id Registered Widget ID.
  1018.  */
  1019. function wp_dashboard_trigger_widget_control( $widget_control_id = false ) {
  1020.     global $wp_dashboard_control_callbacks;
  1021.  
  1022.     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]) ) {
  1023.         call_user_func( $wp_dashboard_control_callbacks[$widget_control_id], '', array( 'id' => $widget_control_id, 'callback' => $wp_dashboard_control_callbacks[$widget_control_id] ) );
  1024.     }
  1025. }
  1026.  
  1027. /**
  1028.  * The RSS dashboard widget control.
  1029.  *
  1030.  * Sets up $args to be used as input to wp_widget_rss_form(). Handles POST data
  1031.  * from RSS-type widgets.
  1032.  *
  1033.  * @since 2.5.0
  1034.  *
  1035.  * @param string $widget_id
  1036.  * @param array $form_inputs
  1037.  */
  1038. function wp_dashboard_rss_control( $widget_id, $form_inputs = array() ) {
  1039.     if ( !$widget_options = get_option( 'dashboard_widget_options' ) )
  1040.         $widget_options = array();
  1041.  
  1042.     if ( !isset($widget_options[$widget_id]) )
  1043.         $widget_options[$widget_id] = array();
  1044.  
  1045.     $number = 1; // Hack to use wp_widget_rss_form()
  1046.     $widget_options[$widget_id]['number'] = $number;
  1047.  
  1048.     if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget-rss'][$number]) ) {
  1049.         $_POST['widget-rss'][$number] = wp_unslash( $_POST['widget-rss'][$number] );
  1050.         $widget_options[$widget_id] = wp_widget_rss_process( $_POST['widget-rss'][$number] );
  1051.         $widget_options[$widget_id]['number'] = $number;
  1052.  
  1053.         // Title is optional. If black, fill it if possible.
  1054.         if ( !$widget_options[$widget_id]['title'] && isset($_POST['widget-rss'][$number]['title']) ) {
  1055.             $rss = fetch_feed($widget_options[$widget_id]['url']);
  1056.             if ( is_wp_error($rss) ) {
  1057.                 $widget_options[$widget_id]['title'] = htmlentities(__('Unknown Feed'));
  1058.             } else {
  1059.                 $widget_options[$widget_id]['title'] = htmlentities(strip_tags($rss->get_title()));
  1060.                 $rss->__destruct();
  1061.                 unset($rss);
  1062.             }
  1063.         }
  1064.         update_option( 'dashboard_widget_options', $widget_options );
  1065.         $locale = get_user_locale();
  1066.         $cache_key = 'dash_v2_' . md5( $widget_id . '_' . $locale );
  1067.         delete_transient( $cache_key );
  1068.     }
  1069.  
  1070.     wp_widget_rss_form( $widget_options[$widget_id], $form_inputs );
  1071. }
  1072.  
  1073.  
  1074. /**
  1075.  * Renders the Events and News dashboard widget.
  1076.  *
  1077.  * @since 4.8.0
  1078.  */
  1079. function wp_dashboard_events_news() {
  1080.     wp_print_community_events_markup();
  1081.  
  1082.     ?>
  1083.  
  1084.     <div class="wordpress-news hide-if-no-js">
  1085.         <?php wp_dashboard_primary(); ?>
  1086.     </div>
  1087.  
  1088.     <p class="community-events-footer">
  1089.         <?php
  1090.             printf(
  1091.                 '<a href="%1$s" target="_blank">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
  1092.                 'https://make.wordpress.org/community/meetups-landing-page',
  1093.                 __( 'Meetups' ),
  1094.                 /* translators: accessibility text */
  1095.                 __( '(opens in a new window)' )
  1096.             );
  1097.         ?>
  1098.  
  1099.         |
  1100.  
  1101.         <?php
  1102.             printf(
  1103.                 '<a href="%1$s" target="_blank">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
  1104.                 'https://central.wordcamp.org/schedule/',
  1105.                 __( 'WordCamps' ),
  1106.                 /* translators: accessibility text */
  1107.                 __( '(opens in a new window)' )
  1108.             );
  1109.         ?>
  1110.  
  1111.         |
  1112.  
  1113.         <?php
  1114.             printf(
  1115.                 '<a href="%1$s" target="_blank">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
  1116.                 /* translators: If a Rosetta site exists (e.g. https://es.wordpress.org/news/), then use that. Otherwise, leave untranslated. */
  1117.                 esc_url( _x( 'https://wordpress.org/news/', 'Events and News dashboard widget' ) ),
  1118.                 __( 'News' ),
  1119.                 /* translators: accessibility text */
  1120.                 __( '(opens in a new window)' )
  1121.             );
  1122.         ?>
  1123.     </p>
  1124.  
  1125.     <?php
  1126. }
  1127.  
  1128. /**
  1129.  * Prints the markup for the Community Events section of the Events and News Dashboard widget.
  1130.  *
  1131.  * @since 4.8.0
  1132.  */
  1133. function wp_print_community_events_markup() {
  1134.     ?>
  1135.  
  1136.     <div class="community-events-errors notice notice-error inline hide-if-js">
  1137.         <p class="hide-if-js">
  1138.             <?php _e( 'This widget requires JavaScript.' ); ?>
  1139.         </p>
  1140.  
  1141.         <p class="community-events-error-occurred" aria-hidden="true">
  1142.             <?php _e( 'An error occurred. Please try again.' ); ?>
  1143.         </p>
  1144.  
  1145.         <p class="community-events-could-not-locate" aria-hidden="true"></p>
  1146.     </div>
  1147.  
  1148.     <div class="community-events-loading hide-if-no-js">
  1149.         <?php _e( 'Loading…' ); ?>
  1150.     </div>
  1151.  
  1152.     <?php
  1153.     /*
  1154.      * Hide the main element when the page first loads, because the content
  1155.      * won't be ready until wp.communityEvents.renderEventsTemplate() has run.
  1156.      */
  1157.     ?>
  1158.     <div id="community-events" class="community-events" aria-hidden="true">
  1159.         <div class="activity-block">
  1160.             <p>
  1161.                 <span id="community-events-location-message"></span>
  1162.  
  1163.                 <button class="button-link community-events-toggle-location" aria-label="<?php esc_attr_e( 'Edit city' ); ?>" aria-expanded="false">
  1164.                     <span class="dashicons dashicons-edit"></span>
  1165.                 </button>
  1166.             </p>
  1167.  
  1168.             <form class="community-events-form" aria-hidden="true" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" method="post">
  1169.                 <label for="community-events-location">
  1170.                     <?php _e( 'City:' ); ?>
  1171.                 </label>
  1172.                 <?php
  1173.                 /* translators: Replace with a city related to your locale.
  1174.                  * Test that it matches the expected location and has upcoming
  1175.                  * events before including it. If no cities related to your
  1176.                  * locale have events, then use a city related to your locale
  1177.                  * that would be recognizable to most users. Use only the city
  1178.                  * name itself, without any region or country. Use the endonym
  1179.                  * (native locale name) instead of the English name if possible.
  1180.                  */
  1181.                 ?>
  1182.                 <input id="community-events-location" class="regular-text" type="text" name="community-events-location" placeholder="<?php esc_attr_e( 'Cincinnati' ); ?>" />
  1183.  
  1184.                 <?php submit_button( __( 'Submit' ), 'secondary', 'community-events-submit', false ); ?>
  1185.  
  1186.                 <button class="community-events-cancel button-link" type="button" aria-expanded="false">
  1187.                     <?php _e( 'Cancel' ); ?>
  1188.                 </button>
  1189.  
  1190.                 <span class="spinner"></span>
  1191.             </form>
  1192.         </div>
  1193.  
  1194.         <ul class="community-events-results activity-block last"></ul>
  1195.     </div>
  1196.  
  1197.     <?php
  1198. }
  1199.  
  1200. /**
  1201.  * Renders the events templates for the Event and News widget.
  1202.  *
  1203.  * @since 4.8.0
  1204.  */
  1205. function wp_print_community_events_templates() {
  1206.     ?>
  1207.  
  1208.     <script id="tmpl-community-events-attend-event-near" type="text/template">
  1209.         <?php printf(
  1210.             /* translators: %s: the name of a city */
  1211.             __( 'Attend an upcoming event near %s.' ),
  1212.             '<strong>{{ data.location.description }}</strong>'
  1213.         ); ?>
  1214.     </script>
  1215.  
  1216.     <script id="tmpl-community-events-could-not-locate" type="text/template">
  1217.         <?php printf(
  1218.             /* translators: %s is the name of the city we couldn't locate.
  1219.              * Replace the examples with cities in your locale, but test
  1220.              * that they match the expected location before including them.
  1221.              * Use endonyms (native locale names) whenever possible.
  1222.              */
  1223.             __( 'We couldn’t locate %s. Please try another nearby city. For example: Kansas City; Springfield; Portland.' ),
  1224.             '<em>{{data.unknownCity}}</em>'
  1225.         ); ?>
  1226.     </script>
  1227.  
  1228.     <script id="tmpl-community-events-event-list" type="text/template">
  1229.         <# _.each( data.events, function( event ) { #>
  1230.             <li class="event event-{{ event.type }} wp-clearfix">
  1231.                 <div class="event-info">
  1232.                     <div class="dashicons event-icon" aria-hidden="true"></div>
  1233.                     <div class="event-info-inner">
  1234.                         <a class="event-title" href="{{ event.url }}">{{ event.title }}</a>
  1235.                         <span class="event-city">{{ event.location.location }}</span>
  1236.                     </div>
  1237.                 </div>
  1238.  
  1239.                 <div class="event-date-time">
  1240.                     <span class="event-date">{{ event.formatted_date }}</span>
  1241.                     <# if ( 'meetup' === event.type ) { #>
  1242.                         <span class="event-time">{{ event.formatted_time }}</span>
  1243.                     <# } #>
  1244.                 </div>
  1245.             </li>
  1246.         <# } ) #>
  1247.     </script>
  1248.  
  1249.     <script id="tmpl-community-events-no-upcoming-events" type="text/template">
  1250.         <li class="event-none">
  1251.             <# if ( data.location.description ) { #>
  1252.                 <?php printf(
  1253.                     /* translators: 1: the city the user searched for, 2: meetup organization documentation URL */
  1254.                     __( 'There aren’t any events scheduled near %1$s at the moment. Would you like to <a href="%2$s">organize one</a>?' ),
  1255.                     '{{ data.location.description }}',
  1256.                     __( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' )
  1257.                 ); ?>
  1258.  
  1259.             <# } else { #>
  1260.                 <?php printf(
  1261.                     /* translators: %s: meetup organization documentation URL */
  1262.                     __( 'There aren’t any events scheduled near you at the moment. Would you like to <a href="%s">organize one</a>?' ),
  1263.                     __( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' )
  1264.                 ); ?>
  1265.             <# } #>
  1266.         </li>
  1267.     </script>
  1268.     <?php
  1269. }
  1270.  
  1271. /**
  1272.  * WordPress News dashboard widget.
  1273.  *
  1274.  * @since 2.7.0
  1275.  * @since 4.8.0 Removed popular plugins feed.
  1276.  */
  1277. function wp_dashboard_primary() {
  1278.     $feeds = array(
  1279.         'news' => array(
  1280.  
  1281.             /**
  1282.              * Filters the primary link URL for the 'WordPress News' dashboard widget.
  1283.              *
  1284.              * @since 2.5.0
  1285.              *
  1286.              * @param string $link The widget's primary link URL.
  1287.              */
  1288.             'link' => apply_filters( 'dashboard_primary_link', __( 'https://wordpress.org/news/' ) ),
  1289.  
  1290.             /**
  1291.              * Filters the primary feed URL for the 'WordPress News' dashboard widget.
  1292.              *
  1293.              * @since 2.3.0
  1294.              *
  1295.              * @param string $url The widget's primary feed URL.
  1296.              */
  1297.             'url' => apply_filters( 'dashboard_primary_feed', __( 'http://wordpress.org/news/feed/' ) ),
  1298.  
  1299.             /**
  1300.              * Filters the primary link title for the 'WordPress News' dashboard widget.
  1301.              *
  1302.              * @since 2.3.0
  1303.              *
  1304.              * @param string $title Title attribute for the widget's primary link.
  1305.              */
  1306.             'title'        => apply_filters( 'dashboard_primary_title', __( 'WordPress Blog' ) ),
  1307.             'items'        => 1,
  1308.             'show_summary' => 0,
  1309.             'show_author'  => 0,
  1310.             'show_date'    => 0,
  1311.         ),
  1312.         'planet' => array(
  1313.  
  1314.             /**
  1315.              * Filters the secondary link URL for the 'WordPress News' dashboard widget.
  1316.              *
  1317.              * @since 2.3.0
  1318.              *
  1319.              * @param string $link The widget's secondary link URL.
  1320.              */
  1321.             'link' => apply_filters( 'dashboard_secondary_link', __( 'https://planet.wordpress.org/' ) ),
  1322.  
  1323.             /**
  1324.              * Filters the secondary feed URL for the 'WordPress News' dashboard widget.
  1325.              *
  1326.              * @since 2.3.0
  1327.              *
  1328.              * @param string $url The widget's secondary feed URL.
  1329.              */
  1330.             'url' => apply_filters( 'dashboard_secondary_feed', __( 'https://planet.wordpress.org/feed/' ) ),
  1331.  
  1332.             /**
  1333.              * Filters the secondary link title for the 'WordPress News' dashboard widget.
  1334.              *
  1335.              * @since 2.3.0
  1336.              *
  1337.              * @param string $title Title attribute for the widget's secondary link.
  1338.              */
  1339.             'title'        => apply_filters( 'dashboard_secondary_title', __( 'Other WordPress News' ) ),
  1340.  
  1341.             /**
  1342.              * Filters the number of secondary link items for the 'WordPress News' dashboard widget.
  1343.              *
  1344.              * @since 4.4.0
  1345.              *
  1346.              * @param string $items How many items to show in the secondary feed.
  1347.              */
  1348.             'items'        => apply_filters( 'dashboard_secondary_items', 3 ),
  1349.             'show_summary' => 0,
  1350.             'show_author'  => 0,
  1351.             'show_date'    => 0,
  1352.         )
  1353.     );
  1354.  
  1355.     wp_dashboard_cached_rss_widget( 'dashboard_primary', 'wp_dashboard_primary_output', $feeds );
  1356. }
  1357.  
  1358. /**
  1359.  * Display the WordPress news feeds.
  1360.  *
  1361.  * @since 3.8.0
  1362.  * @since 4.8.0 Removed popular plugins feed.
  1363.  *
  1364.  * @param string $widget_id Widget ID.
  1365.  * @param array  $feeds     Array of RSS feeds.
  1366.  */
  1367. function wp_dashboard_primary_output( $widget_id, $feeds ) {
  1368.     foreach ( $feeds as $type => $args ) {
  1369.         $args['type'] = $type;
  1370.         echo '<div class="rss-widget">';
  1371.             wp_widget_rss_output( $args['url'], $args );
  1372.         echo "</div>";
  1373.     }
  1374. }
  1375.  
  1376. /**
  1377.  * Display file upload quota on dashboard.
  1378.  *
  1379.  * Runs on the {@see 'activity_box_end'} hook in wp_dashboard_right_now().
  1380.  *
  1381.  * @since 3.0.0
  1382.  *
  1383.  * @return bool|null True if not multisite, user can't upload files, or the space check option is disabled.
  1384.  */
  1385. function wp_dashboard_quota() {
  1386.     if ( !is_multisite() || !current_user_can( 'upload_files' ) || get_site_option( 'upload_space_check_disabled' ) )
  1387.         return true;
  1388.  
  1389.     $quota = get_space_allowed();
  1390.     $used = get_space_used();
  1391.  
  1392.     if ( $used > $quota )
  1393.         $percentused = '100';
  1394.     else
  1395.         $percentused = ( $used / $quota ) * 100;
  1396.     $used_class = ( $percentused >= 70 ) ? ' warning' : '';
  1397.     $used = round( $used, 2 );
  1398.     $percentused = number_format( $percentused );
  1399.  
  1400.     ?>
  1401.     <h3 class="mu-storage"><?php _e( 'Storage Space' ); ?></h3>
  1402.     <div class="mu-storage">
  1403.     <ul>
  1404.         <li class="storage-count">
  1405.             <?php $text = sprintf(
  1406.                 /* translators: %s: number of megabytes */
  1407.                 __( '%s MB Space Allowed' ),
  1408.                 number_format_i18n( $quota )
  1409.             );
  1410.             printf(
  1411.                 '<a href="%1$s">%2$s <span class="screen-reader-text">(%3$s)</span></a>',
  1412.                 esc_url( admin_url( 'upload.php' ) ),
  1413.                 $text,
  1414.                 __( 'Manage Uploads' )
  1415.             ); ?>
  1416.         </li><li class="storage-count <?php echo $used_class; ?>">
  1417.             <?php $text = sprintf(
  1418.                 /* translators: 1: number of megabytes, 2: percentage */
  1419.                 __( '%1$s MB (%2$s%%) Space Used' ),
  1420.                 number_format_i18n( $used, 2 ),
  1421.                 $percentused
  1422.             );
  1423.             printf(
  1424.                 '<a href="%1$s" class="musublink">%2$s <span class="screen-reader-text">(%3$s)</span></a>',
  1425.                 esc_url( admin_url( 'upload.php' ) ),
  1426.                 $text,
  1427.                 __( 'Manage Uploads' )
  1428.             ); ?>
  1429.         </li>
  1430.     </ul>
  1431.     </div>
  1432.     <?php
  1433. }
  1434.  
  1435. // Display Browser Nag Meta Box
  1436. function wp_dashboard_browser_nag() {
  1437.     $notice = '';
  1438.     $response = wp_check_browser_version();
  1439.  
  1440.     if ( $response ) {
  1441.         if ( $response['insecure'] ) {
  1442.             /* translators: %s: browser name and link */
  1443.             $msg = sprintf( __( "It looks like you're using an insecure version of %s. Using an outdated browser makes your computer unsafe. For the best WordPress experience, please update your browser." ),
  1444.                 sprintf( '<a href="%s">%s</a>', esc_url( $response['update_url'] ), esc_html( $response['name'] ) )
  1445.             );
  1446.         } else {
  1447.             /* translators: %s: browser name and link */
  1448.             $msg = sprintf( __( "It looks like you're using an old version of %s. For the best WordPress experience, please update your browser." ),
  1449.                 sprintf( '<a href="%s">%s</a>', esc_url( $response['update_url'] ), esc_html( $response['name'] ) )
  1450.             );
  1451.         }
  1452.  
  1453.         $browser_nag_class = '';
  1454.         if ( !empty( $response['img_src'] ) ) {
  1455.             $img_src = ( is_ssl() && ! empty( $response['img_src_ssl'] ) )? $response['img_src_ssl'] : $response['img_src'];
  1456.  
  1457.             $notice .= '<div class="alignright browser-icon"><a href="' . esc_attr($response['update_url']) . '"><img src="' . esc_attr( $img_src ) . '" alt="" /></a></div>';
  1458.             $browser_nag_class = ' has-browser-icon';
  1459.         }
  1460.         $notice .= "<p class='browser-update-nag{$browser_nag_class}'>{$msg}</p>";
  1461.  
  1462.         $browsehappy = 'https://browsehappy.com/';
  1463.         $locale = get_user_locale();
  1464.         if ( 'en_US' !== $locale )
  1465.             $browsehappy = add_query_arg( 'locale', $locale, $browsehappy );
  1466.  
  1467.         $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>';
  1468.         $notice .= '<p class="hide-if-no-js"><a href="" class="dismiss" aria-label="' . esc_attr__( 'Dismiss the browser warning panel' ) . '">' . __( 'Dismiss' ) . '</a></p>';
  1469.         $notice .= '<div class="clear"></div>';
  1470.     }
  1471.  
  1472.     /**
  1473.     * Filters the notice output for the 'Browse Happy' nag meta box.
  1474.     *
  1475.     * @since 3.2.0
  1476.     *
  1477.     * @param string $notice   The notice content.
  1478.     * @param array  $response An array containing web browser information.
  1479.     */
  1480.     echo apply_filters( 'browse-happy-notice', $notice, $response );
  1481. }
  1482.  
  1483. /**
  1484.  * @since 3.2.0
  1485.  *
  1486.  * @param array $classes
  1487.  * @return array
  1488.  */
  1489. function dashboard_browser_nag_class( $classes ) {
  1490.     $response = wp_check_browser_version();
  1491.  
  1492.     if ( $response && $response['insecure'] )
  1493.         $classes[] = 'browser-insecure';
  1494.  
  1495.     return $classes;
  1496. }
  1497.  
  1498. /**
  1499.  * Check if the user needs a browser update
  1500.  *
  1501.  * @since 3.2.0
  1502.  *
  1503.  * @return array|bool False on failure, array of browser data on success.
  1504.  */
  1505. function wp_check_browser_version() {
  1506.     if ( empty( $_SERVER['HTTP_USER_AGENT'] ) )
  1507.         return false;
  1508.  
  1509.     $key = md5( $_SERVER['HTTP_USER_AGENT'] );
  1510.  
  1511.     if ( false === ($response = get_site_transient('browser_' . $key) ) ) {
  1512.         // include an unmodified $wp_version
  1513.         include( ABSPATH . WPINC . '/version.php' );
  1514.  
  1515.         $url = 'http://api.wordpress.org/core/browse-happy/1.1/';
  1516.         $options = array(
  1517.             'body'       => array( 'useragent' => $_SERVER['HTTP_USER_AGENT'] ),
  1518.             'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url( '/' )
  1519.         );
  1520.  
  1521.         if ( wp_http_supports( array( 'ssl' ) ) ) {
  1522.             $url = set_url_scheme( $url, 'https' );
  1523.         }
  1524.  
  1525.         $response = wp_remote_post( $url, $options );
  1526.  
  1527.         if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
  1528.             return false;
  1529.  
  1530.         /**
  1531.          * Response should be an array with:
  1532.          *  'platform' - string - A user-friendly platform name, if it can be determined
  1533.          *  'name' - string - A user-friendly browser name
  1534.          *  'version' - string - The version of the browser the user is using
  1535.          *  'current_version' - string - The most recent version of the browser
  1536.          *  'upgrade' - boolean - Whether the browser needs an upgrade
  1537.          *  'insecure' - boolean - Whether the browser is deemed insecure
  1538.          *  'update_url' - string - The url to visit to upgrade
  1539.          *  'img_src' - string - An image representing the browser
  1540.          *  'img_src_ssl' - string - An image (over SSL) representing the browser
  1541.          */
  1542.         $response = json_decode( wp_remote_retrieve_body( $response ), true );
  1543.  
  1544.         if ( ! is_array( $response ) )
  1545.             return false;
  1546.  
  1547.         set_site_transient( 'browser_' . $key, $response, WEEK_IN_SECONDS );
  1548.     }
  1549.  
  1550.     return $response;
  1551. }
  1552.  
  1553. /**
  1554.  * Empty function usable by plugins to output empty dashboard widget (to be populated later by JS).
  1555.  */
  1556. function wp_dashboard_empty() {}
  1557.  
  1558. /**
  1559.  * Displays a welcome panel to introduce users to WordPress.
  1560.  *
  1561.  * @since 3.3.0
  1562.  */
  1563. function wp_welcome_panel() {
  1564.     ?>
  1565.     <div class="welcome-panel-content">
  1566.     <h2><?php _e( 'Welcome to WordPress!' ); ?></h2>
  1567.     <p class="about-description"><?php _e( 'We’ve assembled some links to get you started:' ); ?></p>
  1568.     <div class="welcome-panel-column-container">
  1569.     <div class="welcome-panel-column">
  1570.         <?php if ( current_user_can( 'customize' ) ) : ?>
  1571.             <h3><?php _e( 'Get Started' ); ?></h3>
  1572.             <a class="button button-primary button-hero load-customize hide-if-no-customize" href="<?php echo wp_customize_url(); ?>"><?php _e( 'Customize Your Site' ); ?></a>
  1573.         <?php endif; ?>
  1574.         <a class="button button-primary button-hero hide-if-customize" href="<?php echo admin_url( 'themes.php' ); ?>"><?php _e( 'Customize Your Site' ); ?></a>
  1575.         <?php if ( current_user_can( 'install_themes' ) || ( current_user_can( 'switch_themes' ) && count( wp_get_themes( array( 'allowed' => true ) ) ) > 1 ) ) : ?>
  1576.             <?php $themes_link = current_user_can( 'customize' ) ? add_query_arg( 'autofocus[panel]', 'themes', admin_url( 'customize.php' ) ) : admin_url( 'themes.php' ); ?>
  1577.             <p class="hide-if-no-customize"><?php printf( __( 'or, <a href="%s">change your theme completely</a>' ), $themes_link ); ?></p>
  1578.         <?php endif; ?>
  1579.     </div>
  1580.     <div class="welcome-panel-column">
  1581.         <h3><?php _e( 'Next Steps' ); ?></h3>
  1582.         <ul>
  1583.         <?php if ( 'page' == get_option( 'show_on_front' ) && ! get_option( 'page_for_posts' ) ) : ?>
  1584.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-edit-page">' . __( 'Edit your front page' ) . '</a>', get_edit_post_link( get_option( 'page_on_front' ) ) ); ?></li>
  1585.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-add-page">' . __( 'Add additional pages' ) . '</a>', admin_url( 'post-new.php?post_type=page' ) ); ?></li>
  1586.         <?php elseif ( 'page' == get_option( 'show_on_front' ) ) : ?>
  1587.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-edit-page">' . __( 'Edit your front page' ) . '</a>', get_edit_post_link( get_option( 'page_on_front' ) ) ); ?></li>
  1588.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-add-page">' . __( 'Add additional pages' ) . '</a>', admin_url( 'post-new.php?post_type=page' ) ); ?></li>
  1589.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-write-blog">' . __( 'Add a blog post' ) . '</a>', admin_url( 'post-new.php' ) ); ?></li>
  1590.         <?php else : ?>
  1591.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-write-blog">' . __( 'Write your first blog post' ) . '</a>', admin_url( 'post-new.php' ) ); ?></li>
  1592.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-add-page">' . __( 'Add an About page' ) . '</a>', admin_url( 'post-new.php?post_type=page' ) ); ?></li>
  1593.         <?php endif; ?>
  1594.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-view-site">' . __( 'View your site' ) . '</a>', home_url( '/' ) ); ?></li>
  1595.         </ul>
  1596.     </div>
  1597.     <div class="welcome-panel-column welcome-panel-last">
  1598.         <h3><?php _e( 'More Actions' ); ?></h3>
  1599.         <ul>
  1600.         <?php if ( current_theme_supports( 'widgets' ) || current_theme_supports( 'menus' ) ) : ?>
  1601.             <li><div class="welcome-icon welcome-widgets-menus"><?php
  1602.                 if ( current_theme_supports( 'widgets' ) && current_theme_supports( 'menus' ) ) {
  1603.                     printf( __( 'Manage <a href="%1$s">widgets</a> or <a href="%2$s">menus</a>' ),
  1604.                         admin_url( 'widgets.php' ), admin_url( 'nav-menus.php' ) );
  1605.                 } elseif ( current_theme_supports( 'widgets' ) ) {
  1606.                     echo '<a href="' . admin_url( 'widgets.php' ) . '">' . __( 'Manage widgets' ) . '</a>';
  1607.                 } else {
  1608.                     echo '<a href="' . admin_url( 'nav-menus.php' ) . '">' . __( 'Manage menus' ) . '</a>';
  1609.                 }
  1610.             ?></div></li>
  1611.         <?php endif; ?>
  1612.         <?php if ( current_user_can( 'manage_options' ) ) : ?>
  1613.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-comments">' . __( 'Turn comments on or off' ) . '</a>', admin_url( 'options-discussion.php' ) ); ?></li>
  1614.         <?php endif; ?>
  1615.             <li><?php printf( '<a href="%s" class="welcome-icon welcome-learn-more">' . __( 'Learn more about getting started' ) . '</a>', __( 'https://codex.wordpress.org/First_Steps_With_WordPress' ) ); ?></li>
  1616.         </ul>
  1617.     </div>
  1618.     </div>
  1619.     </div>
  1620.     <?php
  1621. }
  1622.