The Underscores (_s) theme with Sass and Gulp Part 10: all about widgets

==================================================================

On this page:

  1. Get to know widget areas, aka "sidebars".
  2. Use the Monster Widget plugin to test all widgets.
  3. Applying CSS to the widget area.
  4. Add custom styles to specific widgets.
  5. Add an optional widget area to the footer.

==================================================================

52. Register and display widget areas, aka "sidebars".

Github repo branch: part10_52

Widget areas are defined in functions.php. Here we have a function called pre_underscores_widgets_init(), and inside that function we have register_sidebar. In WordPress the word sidebar actually means 'widget-area' and can also be a sidebar, but doesn't have to be. For example, when you want to add a new widget area, you would register a new sidebar. We actually are registering a widget area here . Inside the register sidebar function, we pass a number of different parameters, including the name.

52.1. Register the widget area.

/**
* Register widget area.
*
* @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
*/
function pre_underscores_widgets_init() {
register_sidebar( array(
'name'          => esc_html__( 'Sidebar', 'pre_underscores' ),
'id'            => 'sidebar-1',
'description'   => esc_html__( 'Add widgets here.', 'pre_underscores' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget'  => '</section>',
'before_title'  => '<h2 class="widget-title">',
'after_title'   => '</h2>',
) );
}
add_action( 'widgets_init', 'pre_underscores_widgets_init' );

Register sidebar has a bunch of other parameters too, and you can highly customize the output of the different widgets.

52.2. Display the widget area.

After the widget area is registered, the widget area can be displayed. Create a file 'sidebar.php'. This file will be called when using the function get_sidebar() and will display the widget area. Likewise:

  • sidebar-footer.php willed be called when using get_sidebar('footer')
  • sidebar-top.php willed be called when using get_sidebar('top')
  • etc

In the template file we will check if the widget position with an id of 'sidebar-1' has widgets (is active) attached to it. If so, the widget position is displayed with the dynamic_sidebar() function :

<?php /** * The sidebar containing the main widget area * * @link https://developer.wordpress.org/themes/basics/template-files/#template-partials * * @package Pre_Underscores */

//check if a widget position with id=sidebar-1 exists. if ( ! is_active_sidebar( 'sidebar-1' ) ) { return; } ?>

<aside id="secondary" class="widget-area"> <?php dynamic_sidebar( 'sidebar-1' ); ?> </aside><!-- #secondary -->

code 10.52.1. sidebar.php

==================================================================

53. Use the Monster Widget plugin to test all widgets.

Github repo branch: part10_53

When we start working with widgets, it's important to test your theme against all the available widgets that ship with WordPress out of the box. Now, doing this is a bit of a hassle because you have to go to the Customizer, then go to Widgets, then go to your widget area and all of the widgets individually. Then you have to set each of the widgets up with the most extreme content you can think of. And, needless to say, this is a lot of work. The good news is, you don't have to do this. Instead, we can use the somewhat ridiculously named Monster Widget to solve this problem in on fell swoop. You can see here, I already have the Monster Widget available to me and that's because I added it when I set up the developer plugin. It's one of the recommended plugins we use. Actually, using the Monster Widget is as easy as it can get. First, I'll remove all the widgets I've already set up. Then, I clicked 'Add a Widget' and just 'Add Monster'. The Monster Widget will now display every available widget to me filled in with the most extreme content they can think of. So, here we have every widget in alphabetical order, Archive List, Archives drop down, Calendar, Categories, and so on, and so on.

What we get with the Monster widget are two things. First of all, every single widget that we need to style and make sure works properly for our theme. And, second of all, the most extreme scenario imaginable, where the site owner has chosen to add a ton of widgets into a sidebar or other widgetized area, so we can see what that would look like. This plugin and the Monster Widget is one of those poorly kept secrets that makes WordPress theme development a lot easier. And I use it all the time. So, any time you add a new widget area to your theme, always dump in the Monster Widget, make sure all the widgets look great, and then you can take it out and just put in whatever widgets you actually want to display.

==================================================================

54. Applying CSS to the widget area.

Github repo branch: part10_54

So now, after registering and displaying, it is time to make sure the widgets actually look good. You can find the styles for the widgets in sass/site/secondary/_widgets.scss, ans also below in code 10.54.1

.widget-area {
  margin-top: 1.5em;
  }
.widget {
  margin: 0 0 2em;
  padding: 0 0 2em;
  font-family: $font__sans;
 ul,
  ol {
  padding: .7em 0 0;
  margin-bottom: 0;
  list-style-type: none;
 li {
  display: block;
  line-height: 2em;
 ul,
  ol {
  margin-left: .5em;
 @media screen and (min-width: 30em) {
  margin-left: 1em;
  }
  }
 }
  }
 a {
  font-weight: 600;
  text-decoration: none;
 &:hover,
  &:focus {
  border-bottom: 3px solid $color__interactive;
  }
  }
 /* Make sure select elements fit in widgets. */
  select {
  width: 100%;
  height: 2.5em;
  padding: 10px;
  font-family: $font__sans;
  border: 1px solid #ccc;
  }
}
.widget-title {
  margin-top: 0;
  margin-bottom: .5em;
  font-size: 1.4em;
  }
code 10.54.1. sass/site/secondary/_widgets.scss

Let's look at the HTML structure of widgets so you can see how you can target it using CSS. If we inspect the widget here, you'll see the entire widget area is wrapped in an aside with the ID secondary on the class widget area. This was defined in sidebar.php and it's not part of the widgets themselves, but this is generated by the theme. Then we have the actual widgets and you'll remember from functions.php that each of the widgets is wrapped inside a section. That section has an ID that identifies the widget, then it has two classes, widget and the class that identifies what type of widget this is. Then inside the actual widget we have an h2 with a class widget title. This is the title of the widget itself and then depending on what type of widget it is, we'll have different types of content.

you'll see each of the widgets has the exact same markup. Here we have a section ID and in this case it's the Monster widget placeholder, because we're using the Monster widget. Then we have the class widget and another class that tells us what type of widget it is. That means if we want to style of the widgets the same, which is what we've done so far, all you have to do is target the widget class.

And here's a tip. Chances are you may want to add multiple different widget areas to your site but you want to make sure the widgets have the same look and feel. In that case, just target the widget class and make global styles for all widgets and then if you want to you can create additional styles for specific widget areas later

Looking back at widgets.scss you can now see exactly what I've done. I've grabbed the widget area and given it some margin and padding just to space it apart from everything else and set the font family for all widgets.

Then I target any unordered or ordered list within any of these widget areas and just style them so that they look okay. I make sure all links and widgets are styled the same, all select boxes are styled the same and then finally I apply some basic styling to the widget title. In theory this works fine because now all my widgets are styled exactly the same however, there are some widgets that have custom content so if we scroll down here, you'll see that although the lists look okay and everything, there's certain sections that look kind of drab and there's certain sections where things aren't working properly, let's say this RSS widget looks totally messed up and the Text widget could really use some work, the Tag Cloud is okay but the Nav Menu doesn't look like a menu.

So there's still some work to be done and we'll do that in the next part 55..

==================================================================

55.Add custom styles to specific widgets.

Github repo branch: part10_55

When it comes to styling individual widgets, this tiny little piece of code here, %2$s, on line 6 of the register_sidebar() function, in functions.php turns out to be a vital component. This %2$s calls a variable that inputs the class name for the current widget on display

function pre_underscores_widgets_init() {
register_sidebar( array(
'name'          => esc_html__( 'Sidebar', 'pre_underscores' ),
'id'            => 'sidebar-1',
'description'   => esc_html__( 'Add widgets here.', 'pre_underscores' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget'  => '</section>',
'before_title'  => '<h2 class="widget-title">',
'after_title'   => '</h2>',
) );
}

We see that in the markup, here, for each of the sections, which is a widget, we have the class widgets, and then widget archive, widget archive, calendar, categories, categories, pages, meta, recent comments, and so on. These class names, allow us to create custom styles for specific types of widgets.

<section id="monster-widget-placeholder-1" class="widget widget_archive">...</section>
<section id="monster-widget-placeholder-2" class="widget widget_archive">...</section>
<section id="monster-widget-placeholder-3" class="widget widget_calendar">...</section>
<section id="monster-widget-placeholder-4" class="widget widget_categories">...</section>
...

I've added additional rules to sass/site/secondary/_widgets.scss that target individual widget types. So, here you can see styles for widget archive, widget category, widget search and so on and so on. I do this in the most general way possible by targeting just widget categories, nothing about sidebar or anything else and so that these styles will be inherited any time I display widgets anywhere on the site (see code 10.55.1).

.widget-area {
  margin-top: 1.5em;
  }
.widget {
  margin: 0 0 2em;
  padding: 0 0 2em;
  font-family: $font__sans;
  
  ul,
  ol {
  padding: .7em 0 0;
  margin-bottom: 0;
  list-style-type: none;
 li {
  display: block;
  line-height: 2em;
 ul,
  ol {
  margin-left: .5em;
 @media screen and (min-width: 30em) {
  margin-left: 1em;
  }
  }
  
  }
  }
  
  a {
  font-weight: 600;
  text-decoration: none;
  
  &:hover,
  &:focus {
  border-bottom: 3px solid $color__interactive;
  }
  }
  
  /* Make sure select elements fit in widgets. */
  select {
  width: 100%;
  height: 2.5em;
  padding: 10px;
  font-family: $font__sans;
  border: 1px solid #ccc;
  }
  
  }
.widget-title {
  margin-top: 0;
  margin-bottom: .5em;
  font-size: 1.4em;
  }
/* Archive and Categories widgets */
  .widget_archive li {
  color: #7D7D7D;
  }
.widget_categories .children {
  padding-top: 0;
  }
/* Search widget. */
  .widget_search .search-submit {
  display: none;
  }
/* Pages and Menu widgets */
  .widget_pages .children,
  .widget_nav_menu .sub-menu {
  padding-top: 0;
  padding-bottom: .5em;
  }
.widget_pages,
  .widget_nav_menu {
  
  a {
  display: block;
  padding: 1em 0;
  text-decoration: none;
  border-bottom: 1px dashed hsl(0, 0%, 50%);
  
  &:hover,
  &:focus {
  text-decoration: none;
  border-bottom: 1px dashed hsl(0, 0%, 50%);
  }
  }
  
  li {
  padding: 0;
 }
  
  }

/* Meta widget */
  .widget_meta li {
  padding: 0;
  }
/* Recent comments */
  .widget_recent_comments {
 li {
  line-height: 1.3em;
  padding-bottom: .5em;
  }
  
  a:hover,
  a:focus {
  padding-left: 0;
  }
  
  }
/* RSS widget */
  .widget_rss li {
  margin-bottom: 1em;
  }
  .widget li a.rsswidget {
  padding-right: .5em;
  font-size: 1em;
  line-height: 1.4em;
  }
.rss-date,
  .widget_rss cite {
  color: #333;
  font-size: .8em;
  }
.rssSummary {
  padding: .5em 0;
  font-family: $font__sans;
  font-size: .8em;
  line-height: 1.4em;
  }
/* Search widget */
  .widget_search input[type="search"] {
  box-sizing: border-box;
  width: 100%;
  padding: .5em 1em;
  border: 1px solid #c3c3c3;
  border-radius: 0;
  }
/* Calendar widget */
  .widget_calendar {
  font-weight: 400;
  
  caption {
  padding: .5em 0;
  font-size: 1em;
  font-weight: 500;
  text-align: left;
  }
  
  thead {
  background: transparent;
  color: black;
  
  th {
  border-bottom-width: 2px;
  }
  }
  
  td {
  padding: .2em;
  font-size: .8em;
  text-align: center;
  background: white;
  border: 1px solid hsl(0, 0%, 80%);
  }
  
  th {
  border: none;
  text-align: center;
  }
  
  .pad {
  background: #eaeaea;
  }
  
  a {
  font-weight: 900;
  text-decoration: none;
  }
  
  }
/* Text widget */
  .textwidget {
  font-size: 80%;
  line-height: 1.3em;
  }
  
code 10.55.1. the new _widgets.scss file

They are global styles for all widgets. Scrolling down this list, you'll see some widgets require a lot of extra styling, others do not. Let's take a look on the front end and see what this looks like once all the widgets have been properly styled. The widgets off the top are more or less standard so they don't really need a lot of extra styling, but when I scroll down, I get to something like the calendar widget, and here it's important to make the calendar actually look like a calendar, so here we've used some table styling to make that calendar look and feel quite like a calendar.

Scrolling further down, we encounter the pages widget. This is a menu that points to different pages, so it's styled more like a menu to clearly tell the visitor, this is a menu and you can click on these items, you'll notice the clickable area here has been expanded to fit the full width of the widget area. Continuing down, we have the RSS widget, and this is the one that requires the most extra custom styling. That's because the RSS widget contains a bunch of different elements and they have to be positioned properly, and styled so that it's clear what is text and what is not and so on.

Finally, at the bottom, we have the text widget, which also requires a bit of styling, just so that it doesn't look like a big mess because honestly, the text widget, out of the box, is quite messy. It's worth pointing out that the text here inside the text widget, in the monster widget, is marked up in a really odd way. As you can see, all this text is contained within one paragraph. That's why we don't have any paragraph breaks. Even if you apply a margin or padding on the bottom of each of your paragraphs it won't break this apart because inside here we have a bunch of <br> tags, it's terrible but, you know, people might do this, so you need to account for it.

==================================================================

56. Add an optional widget area to the footer.

Github repo branch: part10_56

56.1. Register he widget

Add the following code to function.php inside the function pre_underscores_widgets_init()

register_sidebar( array(
'name'          => esc_html__( 'Footer Widgets', 'pre_underscores' ),
'id'            => 'footer-1',
'description'   => esc_html__( 'Add footer widgets here.', 'pre_underscores' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget'  => '</section>',
'before_title'  => '<h2 class="widget-title">',
'after_title'   => '</h2>',
) );

The widget area is registered but it's not showing up in the customizer yet because we have yet to display it in a template.

56.2. Display the widget

Copy the file sidebar.php, paste it and rename it to sidebar-footer.php. Inside this file replace two times 'sidebar-1' into 'footer-1' (the name of the id in the register_sidebar() function).

In the footer.php file place the follow code just above the <footer> element

 
<?php get_sidebar('footer'); ?>

Now we can go into sidebar-footer.php again and change the mark up ever so slightly so that it works with my new widget area. The code in sidebar-footer.php should look like this now:

 

<?php
  /**
  * The sidebar containing the main widget area
  *
  * @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
  *
  * @package Pre_Underscores
  */
if ( ! is_active_sidebar( 'footer-1' ) ) {
  return;
  }
  ?>
<aside id="footer-widget-area" class="footer-widgets">
  <?php dynamic_sidebar( 'footer-1' ); ?>
  </aside><!-- #footer-widget-area -->
  

Save, go back and reload the customizer, and now when I go to widgets I have two areas: sidebar and footer widgets. Now, right now I'm displaying the whole sidebar and it makes me scroll up and down a lot, so I'm going to go into the sidebar and remove the monster widget, and then I'll go into footer widgets and add the monster widget there instead. Save and publish, close the customizer, and then I'll go back to my tab where I have browser sync activated. I'll reload the page, and when I scroll down you see here, in the footer, we now have the widgets, and they are full bleed, but this looks awful.

I mean, we are inheriting all the styling for the widgets, but they are not styled for the footers, so they're spanning the full width and it looks wrong. That means we need to apply some CSS. I've added in the necessary CSS for the footer section in the sass/site/secondary/_widgets.scss folder.

 
/* Footer widget stylings */
.footer-widgets {
  margin: 2em 0 0;
  padding: 1em 0;
  background-color: hsl(0, 0%, 10%);
  
  @media screen and (min-width: $query__small) {
  padding: 2em 1em;
  }
  
  .widget {
  flex: 1;
  margin: 0 1em 2em;
  padding-top: 1em;
  
  .original-title {
  color: hsla(0, 0%, 100%, .5);
  }
  }
  
  .widget,
  .widget-title,
  .widget a,
  .widget_calendar thead,
  .rss-date, 
  .widget_rss cite {
  color: white;
  }
  
  .widget_calendar td,
  .widget_calendar a {
  color: black;
  }
  
  @media screen and (min-width: $query__medium) {
  /* Use flex to create a responsive layout */
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  
  /* If only one widget is displayed, make it full width. */
  .widget:only-of-type {
  width: 100%;
  }
 /* If 2 or 3 widgets are displayed, make the second one twice as wide. */
  .widget:nth-last-child(n+2):nth-last-child(-n+3):first-child ~ .widget:nth-child(2) { 
  flex: 2;
  }
  
  /* If 4 or more widgets are displayed, show three across when available. */
  .widget:nth-last-child(n+4), 
  .widget:nth-last-child(n+4) ~ .widget { 
  width: 30%;
  flex: 1 1 30%;
  }
  }
  
  }
  

Go back to the browser, you see now we have a proper footer widget area.

Leave a comment