Accessibility: Widgets: Add theme support to make widgets output list of links wrapped within a `<nav>` element.

Widgets that output list of links can now be wrapped within `<nav>` elements to improve semantics and accessibility.

The `<nav>` elements are also native landmark regions, which helps assistive technology users to navigate through them. Themes can opt-in to this new behavior by declaring support for the new `html5` feature `navigation-widgets`.

Props joedolson, simonjanin, audrasjb, afercia.
Fixes #48170.

Built from https://develop.svn.wordpress.org/trunk@48349


git-svn-id: http://core.svn.wordpress.org/trunk@48118 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Andrea Fercia 2020-07-06 20:44:02 +00:00
parent 1145607a85
commit 04921ffd45
10 changed files with 308 additions and 97 deletions

View File

@ -15,31 +15,33 @@ require_once ABSPATH . WPINC . '/class-walker-nav-menu.php';
* *
* @since 3.0.0 * @since 3.0.0
* @since 4.7.0 Added the `item_spacing` argument. * @since 4.7.0 Added the `item_spacing` argument.
* @since 5.5.0 Added the `container_aria_label` argument.
* *
* @param array $args { * @param array $args {
* Optional. Array of nav menu arguments. * Optional. Array of nav menu arguments.
* *
* @type int|string|WP_Term $menu Desired menu. Accepts a menu ID, slug, name, or object. Default empty. * @type int|string|WP_Term $menu Desired menu. Accepts a menu ID, slug, name, or object. Default empty.
* @type string $menu_class CSS class to use for the ul element which forms the menu. Default 'menu'. * @type string $menu_class CSS class to use for the ul element which forms the menu. Default 'menu'.
* @type string $menu_id The ID that is applied to the ul element which forms the menu. * @type string $menu_id The ID that is applied to the ul element which forms the menu.
* Default is the menu slug, incremented. * Default is the menu slug, incremented.
* @type string $container Whether to wrap the ul, and what to wrap it with. Default 'div'. * @type string $container Whether to wrap the ul, and what to wrap it with. Default 'div'.
* @type string $container_class Class that is applied to the container. Default 'menu-{menu slug}-container'. * @type string $container_class Class that is applied to the container. Default 'menu-{menu slug}-container'.
* @type string $container_id The ID that is applied to the container. Default empty. * @type string $container_id The ID that is applied to the container. Default empty.
* @type callable|bool $fallback_cb If the menu doesn't exist, a callback function will fire. * @type string $container_aria_label The aria-label attribute that is applied to the container when it's a nav element. Default empty.
* Default is 'wp_page_menu'. Set to false for no fallback. * @type callable|bool $fallback_cb If the menu doesn't exist, a callback function will fire.
* @type string $before Text before the link markup. Default empty. * Default is 'wp_page_menu'. Set to false for no fallback.
* @type string $after Text after the link markup. Default empty. * @type string $before Text before the link markup. Default empty.
* @type string $link_before Text before the link text. Default empty. * @type string $after Text after the link markup. Default empty.
* @type string $link_after Text after the link text. Default empty. * @type string $link_before Text before the link text. Default empty.
* @type bool $echo Whether to echo the menu or return it. Default true. * @type string $link_after Text after the link text. Default empty.
* @type int $depth How many levels of the hierarchy are to be included. 0 means all. Default 0. * @type bool $echo Whether to echo the menu or return it. Default true.
* @type object $walker Instance of a custom walker class. Default empty. * @type int $depth How many levels of the hierarchy are to be included. 0 means all. Default 0.
* @type string $theme_location Theme location to be used. Must be registered with register_nav_menu() * @type object $walker Instance of a custom walker class. Default empty.
* in order to be selectable by the user. * @type string $theme_location Theme location to be used. Must be registered with register_nav_menu()
* @type string $items_wrap How the list items should be wrapped. Default is a ul with an id and class. * in order to be selectable by the user.
* Uses printf() format with numbered placeholders. * @type string $items_wrap How the list items should be wrapped. Default is a ul with an id and class.
* @type string $item_spacing Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'preserve'. * Uses printf() format with numbered placeholders.
* @type string $item_spacing Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'preserve'.
* } * }
* @return void|string|false Void if 'echo' argument is true, menu output if 'echo' is false. * @return void|string|false Void if 'echo' argument is true, menu output if 'echo' is false.
* False if there are no items or no menu was found. * False if there are no items or no menu was found.
@ -48,23 +50,24 @@ function wp_nav_menu( $args = array() ) {
static $menu_id_slugs = array(); static $menu_id_slugs = array();
$defaults = array( $defaults = array(
'menu' => '', 'menu' => '',
'container' => 'div', 'container' => 'div',
'container_class' => '', 'container_class' => '',
'container_id' => '', 'container_id' => '',
'menu_class' => 'menu', 'container_aria_label' => '',
'menu_id' => '', 'menu_class' => 'menu',
'echo' => true, 'menu_id' => '',
'fallback_cb' => 'wp_page_menu', 'echo' => true,
'before' => '', 'fallback_cb' => 'wp_page_menu',
'after' => '', 'before' => '',
'link_before' => '', 'after' => '',
'link_after' => '', 'link_before' => '',
'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>', 'link_after' => '',
'item_spacing' => 'preserve', 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
'depth' => 0, 'item_spacing' => 'preserve',
'walker' => '', 'depth' => 0,
'theme_location' => '', 'walker' => '',
'theme_location' => '',
); );
$args = wp_parse_args( $args, $defaults ); $args = wp_parse_args( $args, $defaults );
@ -176,7 +179,8 @@ function wp_nav_menu( $args = array() ) {
$show_container = true; $show_container = true;
$class = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-' . $menu->slug . '-container"'; $class = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-' . $menu->slug . '-container"';
$id = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : ''; $id = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
$nav_menu .= '<' . $args->container . $id . $class . '>'; $aria_label = ( 'nav' === $args->container && $args->container_aria_label ) ? ' aria-label="' . esc_attr( $args->container_aria_label ) . '"' : '';
$nav_menu .= '<' . $args->container . $id . $class . $aria_label . '>';
} }
} }

View File

@ -13,7 +13,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '5.5-alpha-48348'; $wp_version = '5.5-alpha-48349';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.

View File

@ -46,7 +46,8 @@ class WP_Nav_Menu_Widget extends WP_Widget {
return; return;
} }
$title = ! empty( $instance['title'] ) ? $instance['title'] : ''; $default_title = __( 'Menu' );
$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@ -57,10 +58,36 @@ class WP_Nav_Menu_Widget extends WP_Widget {
echo $args['before_title'] . $title . $args['after_title']; echo $args['before_title'] . $title . $args['after_title'];
} }
$nav_menu_args = array( $format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
'fallback_cb' => '',
'menu' => $nav_menu, /**
); * Filters the HTML format of widgets with navigation links.
*
* @since 5.5.0
*
* @param string $format The type of markup to use in widgets with navigation links.
* Accepts 'html5', 'xhtml'.
*/
$format = apply_filters( 'navigation_widgets_format', $format );
if ( 'html5' === $format ) {
// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
$title = trim( strip_tags( $title ) );
$aria_label = $title ? $title : $default_title;
$nav_menu_args = array(
'fallback_cb' => '',
'menu' => $nav_menu,
'container' => 'nav',
'container_aria_label' => $aria_label,
'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
);
} else {
$nav_menu_args = array(
'fallback_cb' => '',
'menu' => $nav_menu,
);
}
/** /**
* Filters the arguments for the Navigation Menu widget. * Filters the arguments for the Navigation Menu widget.

View File

@ -40,7 +40,8 @@ class WP_Widget_Archives extends WP_Widget {
* @param array $instance Settings for the current Archives widget instance. * @param array $instance Settings for the current Archives widget instance.
*/ */
public function widget( $args, $instance ) { public function widget( $args, $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Archives' ); $default_title = __( 'Archives' );
$title = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@ -120,37 +121,60 @@ class WP_Widget_Archives extends WP_Widget {
})(); })();
/* ]]> */ /* ]]> */
</script> </script>
<?php } else { ?>
<ul>
<?php <?php
wp_get_archives( } else {
/** $format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
* Filters the arguments for the Archives widget.
* /**
* @since 2.8.0 * Filters the HTML format of widgets with navigation links.
* @since 4.9.0 Added the `$instance` parameter. *
* * @since 5.5.0
* @see wp_get_archives() *
* * @param string $format The type of markup to use in widgets with navigation links.
* @param array $args An array of Archives option arguments. * Accepts 'html5', 'xhtml'.
* @param array $instance Array of settings for the current widget. */
*/ $format = apply_filters( 'navigation_widgets_format', $format );
apply_filters(
'widget_archives_args', if ( 'html5' === $format ) {
array( // The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
'type' => 'monthly', $title = trim( strip_tags( $title ) );
'show_post_count' => $count, $aria_label = $title ? $title : $default_title;
), echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
$instance }
)
);
?> ?>
</ul>
<?php
}
echo $args['after_widget']; <ul>
<?php
wp_get_archives(
/**
* Filters the arguments for the Archives widget.
*
* @since 2.8.0
* @since 4.9.0 Added the `$instance` parameter.
*
* @see wp_get_archives()
*
* @param array $args An array of Archives option arguments.
* @param array $instance Array of settings for the current widget.
*/
apply_filters(
'widget_archives_args',
array(
'type' => 'monthly',
'show_post_count' => $count,
),
$instance
)
);
?>
</ul>
<?php if ( 'html5' === $format ) : ?>
</nav>
<?php endif; ?>
<?php
echo $args['after_widget'];
}
} }
/** /**

View File

@ -44,7 +44,8 @@ class WP_Widget_Categories extends WP_Widget {
public function widget( $args, $instance ) { public function widget( $args, $instance ) {
static $first_dropdown = true; static $first_dropdown = true;
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Categories' ); $default_title = __( 'Categories' );
$title = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@ -109,23 +110,47 @@ class WP_Widget_Categories extends WP_Widget {
<?php <?php
} else { } else {
?> $format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
<ul>
<?php
$cat_args['title_li'] = '';
/** /**
* Filters the arguments for the Categories widget. * Filters the HTML format of widgets with navigation links.
* *
* @since 2.8.0 * @since 5.5.0
* @since 4.9.0 Added the `$instance` parameter.
* *
* @param array $cat_args An array of Categories widget options. * @param string $format The type of markup to use in widgets with navigation links.
* @param array $instance Array of settings for the current widget. * Accepts 'html5', 'xhtml'.
*/ */
wp_list_categories( apply_filters( 'widget_categories_args', $cat_args, $instance ) ); $format = apply_filters( 'navigation_widgets_format', $format );
if ( 'html5' === $format ) {
// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
$title = trim( strip_tags( $title ) );
$aria_label = $title ? $title : $default_title;
echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
}
?> ?>
</ul>
<ul>
<?php
$cat_args['title_li'] = '';
/**
* Filters the arguments for the Categories widget.
*
* @since 2.8.0
* @since 4.9.0 Added the `$instance` parameter.
*
* @param array $cat_args An array of Categories widget options.
* @param array $instance Array of settings for the current widget.
*/
wp_list_categories( apply_filters( 'widget_categories_args', $cat_args, $instance ) );
?>
</ul>
<?php if ( 'html5' === $format ) : ?>
</nav>
<?php endif; ?>
<?php <?php
} }

View File

@ -42,7 +42,8 @@ class WP_Widget_Meta extends WP_Widget {
* @param array $instance Settings for the current Meta widget instance. * @param array $instance Settings for the current Meta widget instance.
*/ */
public function widget( $args, $instance ) { public function widget( $args, $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Meta' ); $default_title = __( 'Meta' );
$title = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@ -52,12 +53,34 @@ class WP_Widget_Meta extends WP_Widget {
if ( $title ) { if ( $title ) {
echo $args['before_title'] . $title . $args['after_title']; echo $args['before_title'] . $title . $args['after_title'];
} }
$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
/**
* Filters the HTML format of widgets with navigation links.
*
* @since 5.5.0
*
* @param string $format The type of markup to use in widgets with navigation links.
* Accepts 'html5', 'xhtml'.
*/
$format = apply_filters( 'navigation_widgets_format', $format );
if ( 'html5' === $format ) {
// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
$title = trim( strip_tags( $title ) );
$aria_label = $title ? $title : $default_title;
echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
}
?> ?>
<ul>
<ul>
<?php wp_register(); ?> <?php wp_register(); ?>
<li><?php wp_loginout(); ?></li> <li><?php wp_loginout(); ?></li>
<li><a href="<?php echo esc_url( get_bloginfo( 'rss2_url' ) ); ?>"><?php _e( 'Entries feed' ); ?></a></li> <li><a href="<?php echo esc_url( get_bloginfo( 'rss2_url' ) ); ?>"><?php _e( 'Entries feed' ); ?></a></li>
<li><a href="<?php echo esc_url( get_bloginfo( 'comments_rss2_url' ) ); ?>"><?php _e( 'Comments feed' ); ?></a></li> <li><a href="<?php echo esc_url( get_bloginfo( 'comments_rss2_url' ) ); ?>"><?php _e( 'Comments feed' ); ?></a></li>
<?php <?php
/** /**
* Filters the "WordPress.org" list item HTML in the Meta widget. * Filters the "WordPress.org" list item HTML in the Meta widget.
@ -80,10 +103,15 @@ class WP_Widget_Meta extends WP_Widget {
wp_meta(); wp_meta();
?> ?>
</ul>
<?php
echo $args['after_widget']; </ul>
<?php if ( 'html5' === $format ) : ?>
</nav>
<?php endif; ?>
<?php
echo $args['after_widget'];
} }
/** /**

View File

@ -40,7 +40,8 @@ class WP_Widget_Pages extends WP_Widget {
* @param array $instance Settings for the current Pages widget instance. * @param array $instance Settings for the current Pages widget instance.
*/ */
public function widget( $args, $instance ) { public function widget( $args, $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Pages' ); $default_title = __( 'Pages' );
$title = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
/** /**
* Filters the widget title. * Filters the widget title.
@ -89,10 +90,35 @@ class WP_Widget_Pages extends WP_Widget {
if ( $title ) { if ( $title ) {
echo $args['before_title'] . $title . $args['after_title']; echo $args['before_title'] . $title . $args['after_title'];
} }
$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
/**
* Filters the HTML format of widgets with navigation links.
*
* @since 5.5.0
*
* @param string $format The type of markup to use in widgets with navigation links.
* Accepts 'html5', 'xhtml'.
*/
$format = apply_filters( 'navigation_widgets_format', $format );
if ( 'html5' === $format ) {
// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
$title = trim( strip_tags( $title ) );
$aria_label = $title ? $title : $default_title;
echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
}
?> ?>
<ul>
<?php echo $out; ?> <ul>
</ul> <?php echo $out; ?>
</ul>
<?php if ( 'html5' === $format ) : ?>
</nav>
<?php endif; ?>
<?php <?php
echo $args['after_widget']; echo $args['after_widget'];
} }

View File

@ -82,7 +82,8 @@ class WP_Widget_Recent_Comments extends WP_Widget {
$output = ''; $output = '';
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Comments' ); $default_title = __( 'Recent Comments' );
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : $default_title;
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@ -123,6 +124,25 @@ class WP_Widget_Recent_Comments extends WP_Widget {
$recent_comments_id = ( $first_instance ) ? 'recentcomments' : "recentcomments-{$this->number}"; $recent_comments_id = ( $first_instance ) ? 'recentcomments' : "recentcomments-{$this->number}";
$first_instance = false; $first_instance = false;
$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
/**
* Filters the HTML format of widgets with navigation links.
*
* @since 5.5.0
*
* @param string $format The type of markup to use in widgets with navigation links.
* Accepts 'html5', 'xhtml'.
*/
$format = apply_filters( 'navigation_widgets_format', $format );
if ( 'html5' === $format ) {
// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
$title = trim( strip_tags( $title ) );
$aria_label = $title ? $title : $default_title;
$output .= '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
}
$output .= '<ul id="' . esc_attr( $recent_comments_id ) . '">'; $output .= '<ul id="' . esc_attr( $recent_comments_id ) . '">';
if ( is_array( $comments ) && $comments ) { if ( is_array( $comments ) && $comments ) {
// Prime cache for associated posts. (Prime post term cache if we need it for permalinks.) // Prime cache for associated posts. (Prime post term cache if we need it for permalinks.)
@ -141,6 +161,11 @@ class WP_Widget_Recent_Comments extends WP_Widget {
} }
} }
$output .= '</ul>'; $output .= '</ul>';
if ( 'html5' === $format ) {
$output .= '</nav>';
}
$output .= $args['after_widget']; $output .= $args['after_widget'];
echo $output; echo $output;

View File

@ -45,7 +45,8 @@ class WP_Widget_Recent_Posts extends WP_Widget {
$args['widget_id'] = $this->id; $args['widget_id'] = $this->id;
} }
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Posts' ); $default_title = __( 'Recent Posts' );
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : $default_title;
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@ -84,12 +85,34 @@ class WP_Widget_Recent_Posts extends WP_Widget {
return; return;
} }
?> ?>
<?php echo $args['before_widget']; ?> <?php echo $args['before_widget']; ?>
<?php <?php
if ( $title ) { if ( $title ) {
echo $args['before_title'] . $title . $args['after_title']; echo $args['before_title'] . $title . $args['after_title'];
} }
$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
/**
* Filters the HTML format of widgets with navigation links.
*
* @since 5.5.0
*
* @param string $format The type of markup to use in widgets with navigation links.
* Accepts 'html5', 'xhtml'.
*/
$format = apply_filters( 'navigation_widgets_format', $format );
if ( 'html5' === $format ) {
// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
$title = trim( strip_tags( $title ) );
$aria_label = $title ? $title : $default_title;
echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
}
?> ?>
<ul> <ul>
<?php foreach ( $r->posts as $recent_post ) : ?> <?php foreach ( $r->posts as $recent_post ) : ?>
<?php <?php
@ -109,6 +132,10 @@ class WP_Widget_Recent_Posts extends WP_Widget {
</li> </li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
<?php if ( 'html5' === $format ) : ?>
</nav>
<?php endif; ?>
<?php <?php
echo $args['after_widget']; echo $args['after_widget'];
} }

View File

@ -94,7 +94,32 @@ class WP_Widget_RSS extends WP_Widget {
if ( $title ) { if ( $title ) {
echo $args['before_title'] . $title . $args['after_title']; echo $args['before_title'] . $title . $args['after_title'];
} }
$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
/**
* Filters the HTML format of widgets with navigation links.
*
* @since 5.5.0
*
* @param string $format The type of markup to use in widgets with navigation links.
* Accepts 'html5', 'xhtml'.
*/
$format = apply_filters( 'navigation_widgets_format', $format );
if ( 'html5' === $format ) {
// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
$title = trim( strip_tags( $title ) );
$aria_label = $title ? $title : __( 'RSS Feed' );
echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
}
wp_widget_rss_output( $rss, $instance ); wp_widget_rss_output( $rss, $instance );
if ( 'html5' === $format ) {
echo '</nav>';
}
echo $args['after_widget']; echo $args['after_widget'];
if ( ! is_wp_error( $rss ) ) { if ( ! is_wp_error( $rss ) ) {