<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Sam Hermes</title><description>Front-end developer and writer, writing about web development, including CSS, accessibility, JavaScript, and WordPress.</description><link>https://samhermes.com/</link><language>en-us</language><item><title>My first npm package with Vite</title><link>https://samhermes.com/posts/my-first-npm-package-with-vite/</link><guid isPermaLink="true">https://samhermes.com/posts/my-first-npm-package-with-vite/</guid><pubDate>Sun, 27 Sep 2026 21:28:00 GMT</pubDate><content:encoded>&lt;p&gt;Getting a package published on npm has long been a mystery to me. There are too many little details that have to be just right, and I was confused about what the end product was even supposed to be.&lt;/p&gt;
&lt;p&gt;Vite really gave me the push that I needed to bring it all together. It offers a &lt;a href=&quot;https://vite.dev/guide/build#library-mode&quot;&gt;“library” mode&lt;/a&gt;, which handles some of the tricky bits behind the scenes. I think this is where I had given up in the past. It bundles the code and outputs it in two formats, which is good for compatibility.&lt;/p&gt;
&lt;p&gt;Next, a key part is adding &lt;code&gt;&quot;type&quot;: &quot;module&quot;&lt;/code&gt; to the package.json file. &lt;a href=&quot;https://nodejs.org/api/packages.html#type&quot;&gt;This is a signal to Node.js&lt;/a&gt; to use the files you’ve created as a module, and allow those who’ve installed your package to import it in that way.&lt;/p&gt;
&lt;p&gt;For the &lt;a href=&quot;https://www.npmjs.com/package/@samhermes/alexander&quot;&gt;Alexander package&lt;/a&gt; that I published, here’s the new entries in package.json that I made, including the &lt;code&gt;type&lt;/code&gt;. This also shows the two formats that have been output, and I’ve included &lt;code&gt;files&lt;/code&gt; here so that it will install both the &lt;code&gt;dist&lt;/code&gt; and &lt;code&gt;scss&lt;/code&gt; folder when someone adds it to their project (the Sass files can be imported directly).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;type&quot;: &quot;module&quot;,
&quot;main&quot;: &quot;dist/alexander.js&quot;,
&quot;exports&quot;: {
  &quot;.&quot;: {
    &quot;import&quot;: &quot;./dist/alexander.js&quot;,
    &quot;require&quot;: &quot;./dist/alexander.umd.cjs&quot;
  }
},
&quot;files&quot;: [
  &quot;dist&quot;,
  &quot;scss&quot;
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once this was set up, I had to decide whether to &lt;a href=&quot;https://docs.npmjs.com/cli/v12/using-npm/scope&quot;&gt;scope&lt;/a&gt; the package or not. If scoped, that would mean it would live at &lt;code&gt;@[username]/[package-name]&lt;/code&gt;. I had a generically-named package, so I decided to scope it. For this, I updated the &lt;code&gt;name&lt;/code&gt; field of package.json to reflect the structure.&lt;/p&gt;
&lt;p&gt;Now, to publish to npm, you just need to be signed in on the command line, and then run the &lt;a href=&quot;https://docs.npmjs.com/cli/v12/commands/npm-publish&quot;&gt;&lt;code&gt;publish&lt;/code&gt;&lt;/a&gt; command.&lt;/p&gt;
&lt;p&gt;Sign in with &lt;code&gt;npm login&lt;/code&gt;, which will take you to your browser and back. Once that is complete, you’re ready to publish. In my case, because the package was scoped, I needed to specify that the package should be public. That can be done by running &lt;code&gt;npm publish --access public&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To release a new version, the process is very easy. Just increase the version number in the package.json file, and then run the &lt;code&gt;publish&lt;/code&gt; command the same way again.&lt;/p&gt;
</content:encoded></item><item><title>Web Component styling with custom properties</title><link>https://samhermes.com/posts/web-component-styling-custom-properties/</link><guid isPermaLink="true">https://samhermes.com/posts/web-component-styling-custom-properties/</guid><pubDate>Sun, 07 Jun 2026 18:55:00 GMT</pubDate><content:encoded>&lt;p&gt;When you are creating a web component, you may want to expose certain properties to outside styling. For this, custom properties are a great tool. For example, you could set a background color inside of the web component itself, but open it up to outside customization. Additionally, custom properties provide a fallback method, which is a great way to set your own defaults.&lt;/p&gt;
&lt;p&gt;In the custom elements styles, this might look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:host {
  background-color: var(--background-color, purple);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, by targeting the name of the custom element, you could set the updated value. This could be applied outside of the shadow DOM, meaning you’ve crossed the shadow DOM barrier.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;my-custom-element {
  --background-color: pink;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, you could set the custom properties at the root of the document. In this case, it’s probably better to prefix the custom property names to avoid collisions with other custom properties that might be on the page.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:root {
  --my-custom-element--background-color: pink;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method could get out of hand after too many custom properties, at which point it probably makes more sense to apply styles to the element itself as usual. This can be done by targeting the custom element directly and with &lt;code&gt;::part()&lt;/code&gt; to target those inner elements that have been opened up.&lt;/p&gt;
</content:encoded></item><item><title>Why I don’t like utility class CSS frameworks</title><link>https://samhermes.com/posts/why-i-do-not-like-utility-class-css-frameworks/</link><guid isPermaLink="true">https://samhermes.com/posts/why-i-do-not-like-utility-class-css-frameworks/</guid><pubDate>Sun, 24 May 2026 18:10:00 GMT</pubDate><content:encoded>&lt;p&gt;See how I tried not to say Tailwind? Oh wait—oops, did it anyway.&lt;/p&gt;
&lt;h2&gt;A subset of CSS&lt;/h2&gt;
&lt;p&gt;Why would I use a tool that limits the features available to me? I know all of CSS, and I’d like to use it, please. It’s the same reason why I don’t use Bootstrap on every website, it just simply doesn’t fill every use case, nor should it.&lt;/p&gt;
&lt;p&gt;Tailwind is always going to trail behind CSS. Tailwind is always going to have difficulty creating complex selectors. You may say that you could just avoid creating those, but that leads me to my next point...&lt;/p&gt;
&lt;h2&gt;Telling designers no&lt;/h2&gt;
&lt;p&gt;I love designers. I love working with them, I love their attention to detail, I love nerding out. It literally sustains me. Why would I use a tool where I have to tell a designer “no”? They want a one-off pixel value? They want an unusual layout? They want mobile and desktop to work differently from each other? Yeah, I’m going to go ahead and build that. Technology is a tool in service of UX.&lt;/p&gt;
&lt;p&gt;It’s here that I agree with Tailwind purists. Using &lt;code&gt;@apply&lt;/code&gt; is bad. Yes, you can use it to break out and implement one-offs. Yes, you can extend the framework, add your own variables. Push all of this too far, and I really don’t see why you’re using Tailwind. Regular CSS is so powerful now. We have fun things! Sass is barely even needed anymore.&lt;/p&gt;
&lt;h2&gt;Junior developers&lt;/h2&gt;
&lt;p&gt;I don’t want someone coming into the web industry through Tailwind. It’s just like coming in through React. You’re going to mess up a bunch of stuff while you figure out what’s going on. It’s better that we stay closer to the platform when starting out, and although you may feel quite capable of using Tailwind, it’s going to be better for everyone to stay closer to CSS. We aren’t making decisions for just ourselves, we should think of those coming up.&lt;/p&gt;
&lt;h2&gt;Consistency for consistency’s sake&lt;/h2&gt;
&lt;p&gt;Similar to React, these tools become “best practice” somehow, and then it is seen as weird if isn’t used. It moves into a space where no one is actually making a decision to use it, and then spreads from there. I like consistency, but not for bad ideas!&lt;/p&gt;
&lt;p&gt;This creates an environment where team members have to know how to use Tailwind to do their job. Onboarding is more complicated. CSS is an expertise that can be used across frameworks and projects and doesn’t need translation. Onboard one time and you’re good.&lt;/p&gt;
&lt;h2&gt;Documentation&lt;/h2&gt;
&lt;p&gt;If you customize Tailwind at all, the docs are suddenly wrong. Everything in the docs assumes the default config. Change the spacing and suddenly all of the examples in the docs are wrong. Don’t pay attention to those. And the problem is that the docs are needed to work with Tailwind. The naming conventions in Tailwind are so inconsistent. They’re inconsistent across the framework &lt;em&gt;and&lt;/em&gt; they’re inconsistent with CSS.&lt;/p&gt;
&lt;h2&gt;Extensions&lt;/h2&gt;
&lt;p&gt;Find a Tailwind example out in the wild? Well, hopefully you haven’t changed your config too much. If so, you’ll have missing colors, wonky spacing, etc. Tailwind is so tied to a specific config that chances are that you’ll need to do a lot of rework just to make things work in your own codebase. Not so efficient.&lt;/p&gt;
&lt;h2&gt;Ignore the markup&lt;/h2&gt;
&lt;p&gt;Tailwind makes it even easier to ignore the markup that you’re writing. By placing so many classes in the markup, it muddies the water of what the generated markup is. CSS isn’t supposed to be in the markup for this reason, there should be a separation of concerns. We need more focus on good markup, and this gets in the way of that.&lt;/p&gt;
&lt;h2&gt;A proliferation of components&lt;/h2&gt;
&lt;p&gt;Take, for example, a card component. A project might use a series of different layouts for this component, but the underlying markup is exactly the same. Tailwind pushes these out into multiple components, each with different classes for the layout. This encourages a lot of repetition and increases the likelihood for inconsistencies.&lt;/p&gt;
&lt;p&gt;It’s so strange to me that there’s no built-in way to address this. &lt;code&gt;tailwind-merge&lt;/code&gt; is a plugin that can get you part of the way there, but it creates an indeciperable mess if pushed too far. CSS itself is really good at this sort of thing. You can create a series of parent classes and apply them as appropriate based on where a component is used.&lt;/p&gt;
</content:encoded></item><item><title>Adventures in Web Component styling</title><link>https://samhermes.com/posts/adventures-web-component-styling/</link><guid isPermaLink="true">https://samhermes.com/posts/adventures-web-component-styling/</guid><pubDate>Fri, 17 Apr 2026 01:47:00 GMT</pubDate><content:encoded>&lt;p&gt;One of my favorite things about web components is the possibilities they open up for styling. Through the shadow DOM, we can have finer control than usual over how an element fits in to a project’s ecosystem.&lt;/p&gt;
&lt;p&gt;With this, it does require learning how everything works first! We haven’t had anything like this in the web platform before, so it takes a while to get used to. Here’s some things that I learned as I got into it.&lt;/p&gt;
&lt;h2&gt;The shadow DOM is optional&lt;/h2&gt;
&lt;p&gt;As I approached web components, I assumed that the shadow DOM was inherent to custom elements. However, it is not! It is totally optional. You could create a custom element and it would behave like any other element on the page.&lt;/p&gt;
&lt;p&gt;The shadow DOM is most useful if you’re creating a component that might be used in an unknown context or otherwise want to encapsulate its styling. If you’re adding a web component to an existing project, it might actually create an unnecessary limitation.&lt;/p&gt;
&lt;h2&gt;An open or closed shadow DOM has nothing to do with styles&lt;/h2&gt;
&lt;p&gt;Another thing I was surprised to find was that the &lt;code&gt;open&lt;/code&gt; or &lt;code&gt;closed&lt;/code&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#mode&quot;&gt;mode&lt;/a&gt; on the shadow DOM does not affect styling. It communicates the availability of the interior elements to JavaScript.&lt;/p&gt;
&lt;p&gt;My outsider perspective assumed that &lt;code&gt;open&lt;/code&gt; would mean that global styles could reach the elements, and that &lt;code&gt;closed&lt;/code&gt; would mean that you would be starting fresh in that context. However, not the case!&lt;/p&gt;
&lt;h2&gt;Inheritable styles apply to the shadow DOM&lt;/h2&gt;
&lt;p&gt;This one was hard to figure out. Global styles like the &lt;code&gt;font-family&lt;/code&gt; on the &lt;code&gt;body&lt;/code&gt; element will be applied to the shadow DOM. This means that a custom element can settle into a page nicely without extra effort, but you might also find that you’re getting outside styles that you don’t want. This can be remedied by applying &lt;code&gt;all: initial&lt;/code&gt; and starting fresh, or just overriding the styles you don’t want inherited.&lt;/p&gt;
&lt;h2&gt;Styles via &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This is the CSS-in-JS that I’m here for. You can add styles inside of a shadow DOM using a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag. These styles will be only applied to the elements inside of the shadow DOM, so you don’t need to use highly specific selectors.&lt;/p&gt;
&lt;p&gt;To target the custom element itself, there is the &lt;code&gt;:host&lt;/code&gt; pseudo class. As the styles are defined inside of the custom element, &lt;code&gt;:host&lt;/code&gt; allows you to reach up a level in a way you otherwise wouldn’t be able to.&lt;/p&gt;
&lt;p&gt;I like to use Sass, so I was immediately interested to see if I could use Sass and then inject that into the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag. Using Vite, I was able to use &lt;a href=&quot;https://vite.dev/guide/assets#explicit-inline-handling&quot;&gt;the &lt;code&gt;?inline&lt;/code&gt; parameter&lt;/a&gt; on the stylesheet import, which prepared the styles to be inlined. Then, I created the &lt;code&gt;style&lt;/code&gt; tag element using &lt;code&gt;createElement&lt;/code&gt;, added the styles as inner text content, and appended it to the shadow DOM. Magic!&lt;/p&gt;
&lt;h2&gt;Exposing elements to exterior styling with &lt;code&gt;part&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;part&lt;/code&gt; attribute allows for an element to be targeted from outside the bounds of the shadow DOM (or inside it, if you fancy). This can be done with &lt;code&gt;::part()&lt;/code&gt;. The name of the part is passed in as an argument, so you might do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;my-custom-element::part(header) {
  border-bottom: 1px solid pink;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Automatic columns in CSS grid</title><link>https://samhermes.com/posts/automatic-columns-css-grid/</link><guid isPermaLink="true">https://samhermes.com/posts/automatic-columns-css-grid/</guid><pubDate>Tue, 07 Apr 2026 01:05:00 GMT</pubDate><content:encoded>&lt;p&gt;When I’m using CSS Grid, I’ll often set a &lt;code&gt;grid-template-columns&lt;/code&gt; for each breakpoint. Usually, I’m going for something like two columns on mobile, three on tablet, and four on desktop. However, with &lt;code&gt;auto-fit&lt;/code&gt; and &lt;code&gt;minmax()&lt;/code&gt;, this can happen with a single declaration. I’m always forgetting that this is a possibility!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-columns: repeat(auto-fit, minmax(6.25rem, 1fr));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach uses &lt;code&gt;repeat()&lt;/code&gt; to create a series of columns. For the first argument, the &lt;code&gt;count&lt;/code&gt; attribute, it uses &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/repeat#auto-fit&quot;&gt;&lt;code&gt;auto-fit&lt;/code&gt;&lt;/a&gt;. This tells the browser to make as many columns as will fit. This could also use &lt;code&gt;auto-fill&lt;/code&gt;, based on your needs. CSS Tricks has a &lt;a href=&quot;https://css-tricks.com/auto-sizing-columns-css-grid-auto-fill-vs-auto-fit/&quot;&gt;great explainer on the differences&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, it uses &lt;code&gt;minmax()&lt;/code&gt; to set a minimum width for each column, and a maximum. In this example, the minimum is equal to 100px (set in &lt;code&gt;rem&lt;/code&gt;), and the maximum uses  &lt;code&gt;1fr&lt;/code&gt; so that the columns evenly distribute once they are above the minimum.&lt;/p&gt;
</content:encoded></item><item><title>What makes for a good web component?</title><link>https://samhermes.com/posts/what-makes-for-good-web-component/</link><guid isPermaLink="true">https://samhermes.com/posts/what-makes-for-good-web-component/</guid><pubDate>Sat, 04 Apr 2026 17:12:00 GMT</pubDate><content:encoded>&lt;p&gt;As I’ve recently gotten into web components, I was surprised to learn about what makes a good web component and what doesn’t. As most of us do, I went into it with a lot of experience with JavaScript frameworks, but web components are fundamentally different and have their own specific purpose.&lt;/p&gt;
&lt;h2&gt;How much should a web component do?&lt;/h2&gt;
&lt;p&gt;Web components (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components&quot;&gt;MDN Docs&lt;/a&gt;) is a term that encompasses a group of features, and one of those is custom elements. When I think of web components, I think of custom elements. Because of the word “components,” I assumed that custom elements would be similar to other component patterns, which is a common misconception.&lt;/p&gt;
&lt;p&gt;Custom elements work best when they are treated similarly to default elements (the ones available in all browsers, think &lt;code&gt;h2&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;img&lt;/code&gt;). I often thought of the &lt;code&gt;img&lt;/code&gt; element. It has a mix of required and optional attributes on it. It also doesn’t do too much. It does images, that’s it. Custom elements work best that way too. &lt;a href=&quot;https://adactio.com/journal/20618&quot;&gt;Jeremy Keith has a good roundup of this mindset shift.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I used the &lt;a href=&quot;https://nordhealth.design&quot;&gt;Nord Design System&lt;/a&gt; as inspiration as I was thinking about how I might break my custom elements up. Their system is made up of lots and lots of smaller &lt;a href=&quot;https://nordhealth.design/components&quot;&gt;custom elements&lt;/a&gt;, which can be combined to create what we might think of as a “component.” If you look at the code for &lt;a href=&quot;https://nordhealth.design/storybook/?path=/story/components-card--with-form&quot;&gt;this sign in form example in their Storybook&lt;/a&gt;, you can start to see how they’ve accomplished this.&lt;/p&gt;
&lt;h2&gt;How do web components behave?&lt;/h2&gt;
&lt;p&gt;As I was coming at web components with the mindset of a JavaScript framework, I was thinking about a component as something that could have lots of arguments and would react to state changes. However, custom elements don’t do well with lots of arguments, as each argument need to be added to the DOM, like default elements. This clutters things up, which is different from a framework, where those arguments don’t necessarily end up in the markup.&lt;/p&gt;
&lt;p&gt;Additionally, custom elements don’t have a concept of state out of the box. You place the markup for the component on the page, and when the JavaScript for it loads, it gets applied. For anything that needs to change after that, you would need to add handling yourself. Again, this is conceptually similar to the behavior of default elements.&lt;/p&gt;
&lt;p&gt;There are some web component frameworks that add in the concept of state, such as &lt;a href=&quot;https://lit.dev/docs/components/properties/&quot;&gt;Lit’s reactive properties&lt;/a&gt;. I haven’t used any of these frameworks yet, but just the addition of state would be really useful. Fortunately, most of these frameworks are really lightweight and could be useful and a performance win if you find yourself adding a lot of boilerplate code to your custom elements.&lt;/p&gt;
</content:encoded></item><item><title>Accessible pagination pattern for Astro</title><link>https://samhermes.com/posts/accessible-pagination/</link><guid isPermaLink="true">https://samhermes.com/posts/accessible-pagination/</guid><pubDate>Wed, 03 Dec 2025 00:48:00 GMT</pubDate><content:encoded>&lt;p&gt;In the Astro docs, the &lt;a href=&quot;https://docs.astro.build/en/guides/routing/#pagination&quot;&gt;demo code for adding pagination links&lt;/a&gt; is not very accessible. Instead of a list of anchor tags, we should use the &lt;code&gt;nav&lt;/code&gt; element and add some structure around the links to communicate what they are.&lt;/p&gt;
&lt;p&gt;Here’s (approximately) what I’m using on my site instead:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;nav class=&quot;post-list-pagination&quot; aria-labelledby=&quot;post-list-pagination-heading&quot;&amp;gt;
  &amp;lt;h2 id=&quot;post-list-pagination-heading&quot; class=&quot;screen-reader-text&quot;&amp;gt;Pagination&amp;lt;/h2&amp;gt;
  &amp;lt;ul aria-labelledby=&quot;post-list-pagination-heading&quot; role=&quot;list&quot;&amp;gt;
    {page.url.first ? (
      &amp;lt;li&amp;gt;&amp;lt;a href={page.url.first}&amp;gt;First&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    ) : null}

    {page.url.prev ? (
      &amp;lt;li&amp;gt;&amp;lt;a href={page.url.prev}&amp;gt;Previous&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    ) : null}

    &amp;lt;li class=&quot;pagination-current&quot;&amp;gt;Page {page.currentPage} of {page.lastPage}&amp;lt;/li&amp;gt;
    
    {page.url.next ? (
      &amp;lt;li&amp;gt;&amp;lt;a href={page.url.next}&amp;gt;Next&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    ) : null}

    {page.url.last ? (
      &amp;lt;li&amp;gt;&amp;lt;a href={page.url.last}&amp;gt;Last&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    ) : null}
  &amp;lt;/ul&amp;gt;
&amp;lt;/nav&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;nav&lt;/code&gt; element allows someone to jump to the pagination if they are navigating by landmarks.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;h2&lt;/code&gt; element allows a user to jump to the pagination if they are navigation by headings. The &lt;code&gt;id&lt;/code&gt; attribute on the heading allows us to tie it to the &lt;code&gt;nav&lt;/code&gt; and &lt;code&gt;ul&lt;/code&gt; elements to communicate what each are for. The heading is visually hidden using the &lt;code&gt;screen-reader-text&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;role&lt;/code&gt; element on the &lt;code&gt;ul&lt;/code&gt; communicates that the &lt;code&gt;ul&lt;/code&gt; is, in fact, a list, as we’re likely to remove the list styling with CSS. Applying &lt;code&gt;list-style: none;&lt;/code&gt; can remove the meaning of the element.&lt;/p&gt;
</content:encoded></item><item><title>Create a template for paginated collection in Astro</title><link>https://samhermes.com/posts/create-template-for-paginated-collection-astro/</link><guid isPermaLink="true">https://samhermes.com/posts/create-template-for-paginated-collection-astro/</guid><pubDate>Tue, 02 Dec 2025 03:59:00 GMT</pubDate><content:encoded>&lt;p&gt;Astro comes with support for paginated collections out of the box, and it’s easy to get it set up. It’s all powered by &lt;code&gt;paginate()&lt;/code&gt;. The &lt;a href=&quot;https://docs.astro.build/en/guides/routing/#pagination&quot;&gt;Astro docs on Routing cover pagination&lt;/a&gt; in detail. As I was setting up the template to drive the /posts section of my site, a few questions came up.&lt;/p&gt;
&lt;h2&gt;First page route without number&lt;/h2&gt;
&lt;p&gt;On my site, I wanted to take the index page at &lt;code&gt;/posts&lt;/code&gt; and use it as the first page. The Astro docs suggest setting up a template named &lt;code&gt;[page].astro&lt;/code&gt; for paginated collections, but this means that there is no longer a page at &lt;code&gt;/posts&lt;/code&gt;, as a user would need to go to &lt;code&gt;/posts/1&lt;/code&gt; to see the first page.&lt;/p&gt;
&lt;p&gt;To get around this, we can use a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters&quot;&gt;rest parameter&lt;/a&gt; to make the template respond to the route without a page number. I learned this from &lt;a href=&quot;https://stackoverflow.com/a/74889664&quot;&gt;this Stack Overflow answer&lt;/a&gt;. The template filename would become &lt;code&gt;[...page].astro&lt;/code&gt; with this change. Problem solved! You’ll see an &lt;code&gt;index.html&lt;/code&gt; file generated alongside the folders for each page, starting at &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Exempt the first page in the template&lt;/h2&gt;
&lt;p&gt;For the page title, I wanted to use “Posts” on the first page, and then on every other page, append the page number.&lt;/p&gt;
&lt;p&gt;When using the &lt;code&gt;paginate()&lt;/code&gt; function, a &lt;code&gt;page&lt;/code&gt; prop is added with additional information about what page you’re on and what other pages exist. &lt;a href=&quot;https://docs.astro.build/en/guides/routing/#the-page-prop&quot;&gt;See the docs for the full listing&lt;/a&gt;. The prop can be accessed like this: &lt;code&gt;const { page } = Astro.props;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Under &lt;code&gt;page&lt;/code&gt;, we have access to &lt;code&gt;currentPage&lt;/code&gt;. We can check to see if this variable is equal to &lt;code&gt;1&lt;/code&gt; and then handle the page title differently based on that logic.&lt;/p&gt;
&lt;p&gt;In my case, I appended the page number to the title like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{page.currentPage === 1 ? &apos;&apos; : ` - Page ${page.currentPage}`}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Get total number of pages&lt;/h2&gt;
&lt;p&gt;When displaying pagination, I liked to show where a user is at. Are there many more pages? Are we almost at the end?&lt;/p&gt;
&lt;p&gt;The total number of pages can be accessed at &lt;code&gt;page.lastPage&lt;/code&gt;. With this, we can display the current position like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;p&amp;gt;Page {page.currentPage} of {page.lastPage}&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Add current page to title tag&lt;/h2&gt;
&lt;p&gt;To match the h1 on the page, I wanted to updated the title tag to append the page number on each page that isn’t the first. I was able to use the same logic as the h1 and then passed this value through the layout component to the &lt;code&gt;title&lt;/code&gt; tag.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pageTitle = `Posts${page.currentPage === 1 ? &quot;&quot; : ` - Page ${page.currentPage}`}`;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>I love RSS</title><link>https://samhermes.com/posts/i-love-rss/</link><guid isPermaLink="true">https://samhermes.com/posts/i-love-rss/</guid><pubDate>Tue, 02 Dec 2025 01:12:00 GMT</pubDate><content:encoded>&lt;p&gt;I have a confession: I’ve been getting really into RSS. I’ve been using NetNewsWire, and really like it. It’s so easy to add a new feed, and it syncs my read/unread status across devices. I also like the way that the app looks, it feels like just enough structure to be helpful.&lt;/p&gt;
&lt;h2&gt;Reverse chron&lt;/h2&gt;
&lt;p&gt;One of the best features of RSS is that it’s reverse chron. This is so inconsistently presented across websites in a browser, so being able to just look at what’s recently been published through RSS is so handy. It also keeps from getting overwhelmed by related content, or being distracted by something that happened years ago but is being featured high up on a site for some reason.&lt;/p&gt;
&lt;h2&gt;No design&lt;/h2&gt;
&lt;p&gt;For my easily overwhelmed brain, having articles presented in the same format acrosss websites has actually been really nice. I’m a little sad to lose the unique character of each site, but it allows me to just focus on what the author is saying and take that in.&lt;/p&gt;
&lt;p&gt;One downside of this is cases where content has not been formatted in a way that RSS supports, so it ends up coming through as a blob of strange HTML. This happens a lot with image galleries and more interactive elements like that.&lt;/p&gt;
&lt;h2&gt;Publish date and time is complicated&lt;/h2&gt;
&lt;p&gt;One thing I noticed right away is that some sites do not set their publish date and time correctly. It’s either not in the right time zone, or it’s set in the past, or missing. The site that I noticed first was my own! I had been setting the time randomly. I don’t display publish time, just date, on the front end, but missed that this was messing up my RSS feed. I think some other sites are doing something similar, so it’s a good reminder to test the feed. I keep subscribed to my own site just to make sure that things are working correctly.&lt;/p&gt;
&lt;h2&gt;It’s okay to skip&lt;/h2&gt;
&lt;p&gt;Speaking of my overwhelmed brain, it took me a little while to stop reading literally every single thing that came through. This was a tipping point for me where I was able to subscribe to feeds that publish multiple times a day. Before, it was too much stuff, and it kept me from subscribing to some sites that I liked.&lt;/p&gt;
&lt;h2&gt;Why is this a confession&lt;/h2&gt;
&lt;p&gt;I’m a web developer! I make websites! RSS fits in a strange middle ground for me. I don’t want to rely on social media to follow these sites, but it’s hard to get a good overview of what’s been published recently without some sort of mechanism like that. Some websites offer an email newsletter, but this is so inconsistent across sites that it’s not a reliable system for keeping up to date. RSS also means that a site that doesn’t publish very frequently doesn’t get lost in the shuffle.&lt;/p&gt;
</content:encoded></item><item><title>Starting fresh with Stylelint</title><link>https://samhermes.com/posts/starting-fresh-with-stylelint/</link><guid isPermaLink="true">https://samhermes.com/posts/starting-fresh-with-stylelint/</guid><pubDate>Sat, 22 Nov 2025 18:25:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve worked on many a project with an existing Stylelint config, and have worked to maintain consistency with the rules of the specific project. That is certainly familiar territory. What I haven’t done is a real deep dive into how &lt;em&gt;I&lt;/em&gt; would set up Stylelint from the start, and an exploration of some of the questions that come up when you’re starting fresh.&lt;/p&gt;
&lt;p&gt;I first started by installing the &lt;code&gt;stylelint&lt;/code&gt; package through NPM. That, however, was a little too eager. I knew too much. Instead, there’s a tool that handles the install and setup for you! You can run &lt;code&gt;npm create stylelint@latest&lt;/code&gt; and that will walk you through some steps.&lt;/p&gt;
&lt;h2&gt;Sass&lt;/h2&gt;
&lt;p&gt;The first thing I ran into was that the default config that comes with Stylelint is for CSS. This is still a Sassy world, baby, so I installed the Sass version of the config, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install stylelint-config-standard-scss
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I updated the config file to use &lt;code&gt;stylelint-config-standard-scss&lt;/code&gt; in &lt;code&gt;extends&lt;/code&gt; and then uninstalled the &lt;code&gt;stylelint-config-standard&lt;/code&gt; package that had been installed during setup.&lt;/p&gt;
&lt;p&gt;Likewise, the command to run Stylelint on Sass files needs to use the &lt;code&gt;.scss&lt;/code&gt; extension instead of just &lt;code&gt;.css&lt;/code&gt;, like &lt;code&gt;stylelint &quot;**/*.scss&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Okay, let’s get into actually running the tests.&lt;/p&gt;
&lt;h2&gt;:not()&lt;/h2&gt;
&lt;p&gt;One of the first rules that I ran into was a rather minor &lt;code&gt;selector-not-notation&lt;/code&gt;. I was chaining together several &lt;code&gt;:not&lt;/code&gt; rules like &lt;code&gt;:not(.this):not(.that)&lt;/code&gt;, which is apparently not “modern.” Frustratingly, Stylelint makes you choose one approach or the other. I needed to update all my &lt;code&gt;:not&lt;/code&gt; usage or update the rule.&lt;/p&gt;
&lt;h2&gt;rgba()&lt;/h2&gt;
&lt;p&gt;Next up, I got feedback about my usage of &lt;code&gt;rgba()&lt;/code&gt;. Interesting. I did not know that we had thoughts about &lt;code&gt;rgba()&lt;/code&gt;. Apparently the preference is to use &lt;code&gt;rgb()&lt;/code&gt;, and the &lt;a href=&quot;https://stylelint.io/user-guide/rules/color-function-alias-notation/&quot;&gt;Stylelint docs&lt;/a&gt; point to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb&quot;&gt;rgb() page on MDN&lt;/a&gt; to justify this. Fair enough, it does say that &lt;code&gt;rgb()&lt;/code&gt; is recommended instead of &lt;code&gt;rgba()&lt;/code&gt;, but there’s no explanation given there. Now I’m just curious.&lt;/p&gt;
&lt;p&gt;Related to this, I find it unsatisfying that the Stylelint docs present things without explanation, in a mechanical way. It makes me want to just turn off the rule. I don’t know how they arrived at the recommendation they did. I guess it’s more about picking &lt;em&gt;something&lt;/em&gt; rather than having an inconsistent approach.&lt;/p&gt;
&lt;p&gt;I do like that Stylelint seems to be encouraging the latest approach. I’m not sure that it should be forced, but I guess a heavy hand works well. Running it over code catches those instances where maybe you don’t need a hack that you needed before, or the name of a property has been standardized. In my case, &lt;code&gt;grid-gap&lt;/code&gt; could be updated to &lt;code&gt;gap&lt;/code&gt;. That’s a helpful suggestion.&lt;/p&gt;
&lt;h2&gt;Unintended changes in functionality&lt;/h2&gt;
&lt;p&gt;Inevitably, making a code change to adhere to the Stylelint standards will result in a different output than before. Some of these are minor, but some of them break things. It’s hard to catch these without careful review of a site. Even in smaller cases like the &lt;code&gt;rgba()&lt;/code&gt; update, you can accidentally end up with a different color output pretty easily, which could be a pretty dramatic bug if used in a background or other large element.&lt;/p&gt;
&lt;p&gt;Stylelint is often used in pull request tests, preventing code from being merged until the issues have been resolved. This is great for the consistency across a codebase, but can mean introducing bugs at the worst possible moment. The code has potentially been reviewed by all the necessary stakeholders, and an innocent change could mean an immediate hotfix.&lt;/p&gt;
&lt;h2&gt;node_modules size&lt;/h2&gt;
&lt;p&gt;As with most things, installing Stylelint adds a bunch of packages to your project. I would say an alarming number of packages. Looking at the diff of the lock file after installing was painful, as it’s annoying to be adding such a huge number of packages for such a minor feature. I would imagine that Stylelint would be light and small, since it runs so quickly, but I suppose it takes a lot to have so much versatility. I’m curious if there is a lighter weight way to get the same result.&lt;/p&gt;
&lt;h2&gt;Integrating with code editor formatting&lt;/h2&gt;
&lt;p&gt;In VS Code, you can format the current file using the Option-Shift-F shortcut. This uses the editor’s settings to apply formatting, which can be different from what Stylelint is looking for. Additionally, it applies some updates that I don’t like. I wanted to sync these with the Stylelint config, but I haven’t been able to find a way to do this. For the time being, I have updated the following settings:&lt;/p&gt;
&lt;p&gt;[  ] SCSS › Format: Newline Between Rules - checked by default
[x] SCSS › Format: Space Around Selector Separator - unchecked by default&lt;/p&gt;
&lt;p&gt;Information about these settings can be found in &lt;a href=&quot;https://code.visualstudio.com/Docs/languages/CSS#_formatting&quot;&gt;Formatting docs for VS Code&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;My config&lt;/h2&gt;
&lt;p&gt;Here’s the config that I ended up with at the end of this exercise. I expect that it will evolve over time, but this seems like a good starting place for now. I started to explore what other rules I might adjust or apply, but it’s pretty overwhelming to approach it that way. I think that addressing things as they come up in a project is a more reasonable way to go.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default {
  &quot;extends&quot;: [&quot;stylelint-config-standard-scss&quot;],
  &quot;rules&quot;: {
    &quot;media-feature-range-notation&quot;: null,
    &quot;value-keyword-case&quot;: [
      &quot;lower&quot;,
      {
        &quot;camelCaseSvgKeywords&quot;: true
      }
    ],
    &quot;no-descending-specificity&quot;: null,
    &quot;no-invalid-position-at-import-rule&quot;: null,
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;media-feature-range-notation&lt;/code&gt; and &lt;code&gt;no-invalid-position-at-import-rule&lt;/code&gt; are like a backwards compatibility thing, as these updates came from existing code that I wanted to keep the way that it is.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;camelCaseSvgKeywords&lt;/code&gt; came from wanting to keep &lt;code&gt;currentColor&lt;/code&gt; instead of updating it to &lt;code&gt;currentcolor&lt;/code&gt;. A small thing, but I much prefer the camel case.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;no-descending-specificity&lt;/code&gt; is a weird one to me, it was giving errors in places that did not seem to pose an issue at all. The docs speak to this, but I felt it was better to just disable.&lt;/p&gt;
</content:encoded></item><item><title>Remove date from slug in Astro</title><link>https://samhermes.com/posts/remove-date-from-slug-astro/</link><guid isPermaLink="true">https://samhermes.com/posts/remove-date-from-slug-astro/</guid><pubDate>Sat, 11 Oct 2025 23:59:00 GMT</pubDate><content:encoded>&lt;p&gt;When I migrated my site from Eleventy to Astro, I had a bunch of posts that were still using a filename structure from when my site was on Jekyll. All of my posts were stored in markdown with the date first, then the title slug (like &lt;code&gt;YYYY-MM-DD-title-slug.md&lt;/code&gt;). This kept the files in date order and made it easy to reference when I wrote something.&lt;/p&gt;
&lt;p&gt;Out of the box with Astro, those dates were being used in the URL. This makes sense, as they are there! It would be weird if it didn’t. However, I wanted to remove the date to maintain the existing permalinks. In Eleventy, I had been able to specify how to handle the permalinks, but Astro doesn’t appear to have any built-in way to address this at the moment.&lt;/p&gt;
&lt;p&gt;To keep things simple, my first approach to this was to trim the slugs down, as each date is the same length:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;post.id.slice(11)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;File that under “it works!” and also “could be better!” I wanted a more stable solution, and a way that I wouldn’t need to remember to slice every single time. I was performing this slice both in the &lt;code&gt;getStaticPaths()&lt;/code&gt; function in the template file, but also across the site any time I displayed a post in a list. Not so handy.&lt;/p&gt;
&lt;p&gt;I then found a post called &lt;a href=&quot;https://gotofritz.net/blog/migrating-blog-to-astro&quot;&gt;Migrating My Blog to Astro&lt;/a&gt;, where the author &lt;a href=&quot;https://gotofritz.net/blog/migrating-blog-to-astro/#prepend-post-filename-with-date-and-remove-it-when-generating-posts&quot;&gt;discusses the same issue&lt;/a&gt;. They created a reusable function for handling the update, and then used that any time that they needed to get the post slug. I used the function that they created, but had to update it to get the &lt;code&gt;id&lt;/code&gt; instead of &lt;code&gt;slug&lt;/code&gt;. Additionally, my collection was named “posts” instead of “post.” Details. I like that this replacement is specifically looking for a date pattern through regex, so it will fall back cleanly if it isn’t found.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import type { CollectionEntry } from &quot;astro:content&quot;;

export function slugRewrite(post: CollectionEntry&amp;lt;&quot;posts&quot;&amp;gt;) {
  return {
    ...post,
    slug: post.id.replace(/^\d{4}-\d{2}-\d{2}-/, &quot;&quot;),
  } as CollectionEntry&amp;lt;&quot;posts&quot;&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used it in the &lt;code&gt;[...slug].astro&lt;/code&gt; template file like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return posts.map(slugRewrite).map((post) =&amp;gt; ({
	params: { slug: post.slug },
	props: { post },
}));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then in the template partial that I used to display an individual post, I updated the post link to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;href={`/posts/${slugRewrite(post).slug}`}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Share layout files between markdown and astro files in Astro</title><link>https://samhermes.com/posts/share-layout-files-between-markdown-astro-files-astro/</link><guid isPermaLink="true">https://samhermes.com/posts/share-layout-files-between-markdown-astro-files-astro/</guid><pubDate>Sat, 11 Oct 2025 17:04:00 GMT</pubDate><content:encoded>&lt;p&gt;As I migrated my site to Astro, one issue that came up was how to handle the flow of metadata when there are multiple types of file formats. Mainly, markdown stores data in a different way from &lt;code&gt;.astro&lt;/code&gt; files. It’s really nice to be able to mix and match these, but the pages that are generated are visually similar. So, separating them based on file type seemed wasteful.&lt;/p&gt;
&lt;p&gt;I tried a couple of approaches to fix this issue, and first started with trying to merge the layout files and then adding in a lot of conditional checks. I’d default to the &lt;code&gt;.astro&lt;/code&gt; format, and then check for frontmatter data from the markdown files. This ended up with a lot of code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pageTitle = title ?? frontmatter?.title;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This got unwieldy pretty quickly, and didn’t seem like a great system if I were to expand the data that I was passing around. This pushed me towards using props to create a more standardized approach.&lt;/p&gt;
&lt;p&gt;Fortunately, Astro supports nested layout files. This allows for a shared wrapper that applies the outer structure of a page, such as the &lt;code&gt;head&lt;/code&gt; and basic &lt;code&gt;body&lt;/code&gt; wrapper, and then a series of more specific layout files can drive content type specific templates.&lt;/p&gt;
&lt;p&gt;The result of this is that I have a &lt;code&gt;SiteLayout.astro&lt;/code&gt; file that supports a set of props, and then I have other layout files such as &lt;code&gt;PostLayout.astro&lt;/code&gt; and &lt;code&gt;PageLayout.astro&lt;/code&gt; that handle passing the metadata for that content type. This looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;SiteLayout title={frontmatter.title}&amp;gt;
  ...
&amp;lt;/SiteLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Apple Music grievances, in no particular order</title><link>https://samhermes.com/posts/apple-music-grievances-in-no-particular-order/</link><guid isPermaLink="true">https://samhermes.com/posts/apple-music-grievances-in-no-particular-order/</guid><pubDate>Sun, 05 Oct 2025 17:42:00 GMT</pubDate><content:encoded>&lt;p&gt;I enjoy being annoyed, which is why I subscribe to Apple Music. Apple seems to enjoy annoying people, by moving things around and generally not fixing the most confusing parts of the app. A match made in heaven.&lt;/p&gt;
&lt;h2&gt;CarPlay&lt;/h2&gt;
&lt;p&gt;I know, starting this list with CarPlay. We’re already in the weeds. I don’t have an unlimited data plan. Apple Music just does not care. It will start up the radio station I was listening to 3 days ago when I connect my phone to my car. It can’t wait to guzzle up my data plan.&lt;/p&gt;
&lt;p&gt;Every single time I want to pick a song, I have to navigate to the library, scroll to the bottom, and tap on Downloaded. There is no way to make this the default. There is no way to say “only display downloaded music” at an app level.&lt;/p&gt;
&lt;p&gt;As of iOS 26, this is no longer an issue, but previously, the CarPlay version of downloaded music would display every album that had even a single downloaded song. It would display every playlist that had a single downloaded song. This was fine, I guess, except that it was different from the app on my phone. Or, even any other platform. It was just a CarPlay thing. Neat. Why was this the case for so long? Did Liquid Glass finally show them the way?&lt;/p&gt;
&lt;h2&gt;Apple Music the service vs. Apple Music the app&lt;/h2&gt;
&lt;p&gt;Tell me if you’ve heard this one before. For some reason, I’m made aware of the gap (?!) between pages in the Apple Music app where I’m using the app vs the service. Despite these being presented as one in the same, I must manually hop between them.&lt;/p&gt;
&lt;p&gt;On an album in my library, if I’d like to see that artist or album in Apple Music (the service), I need to open the 3 dot menu and select “Open in Apple Music.” This is a WILD thing to say, considering that I’m currently running Apple Music and the album is already open. Also, I am regularly opening this menu. You know it’s bad when I’m reliant on a dropdown just to navigate an app.&lt;/p&gt;
&lt;p&gt;For a little bonus fun, you can accidentally select “Open in iTunes Store,” and find yourself trapped in a page with no navigation, your only option is to buy a single for $1.29. At least the occasional nostalgia hit is fun.&lt;/p&gt;
&lt;h2&gt;The Curious Case of the Backwards Playlist&lt;/h2&gt;
&lt;p&gt;One good thing that Apple has added is a “Favorites” playlist. You can add items to it using the star icon on a song. I like to use this to save songs that I want to listen to later or sort into a playlist. All was well and good until this playlist started playing in reverse order one day on my Mac. Instead of going to the next song, it would go to the previous song. If I played the first song, it would play and then stop.&lt;/p&gt;
&lt;p&gt;I tried a number of ridiculous ways to remedy this, and went on long dives into the internet, trying to find someone else stuck this way. The only way I found to fix it was to remove every song from the playlist and start over. Refreshing, of course, but at what cost?&lt;/p&gt;
&lt;h2&gt;Where did my station go? What happened to my mood?&lt;/h2&gt;
&lt;p&gt;Apple Music loves to rearrange. Lest you forget that it’s not an app on your computer, it will reposition sections and menus on random days without requiring a software update. What whimsy!&lt;/p&gt;
&lt;p&gt;I used to use the stations feature pretty regularly. On the Stations page, it had a section for recently played stations, so I could pick up where I left off pretty easily. This is now gone. Where did it go? Why did it go? I can find the recently played stations on the Home page, but they are intermingled with other things I’ve listened to.&lt;/p&gt;
&lt;p&gt;I also used to use the moods pretty regularly. The chill section was nice to relax to. This was on the Browse page (which is now New, despite the fact that I’ve previously listened to many of the things contained therein), but disappeared one day. You can now scroll through the long, long list on the Search page and find it there. Not chill!&lt;/p&gt;
&lt;h2&gt;A recommendation engine for birds&lt;/h2&gt;
&lt;p&gt;On a higher level, I can’t believe that Apple Music’s recommendation engine hasn’t improved at all since I signed up. Look, it probably has in the background, but have I noticed a change? No.&lt;/p&gt;
&lt;p&gt;The Home screen is full of suggested music. They are both so generic and specific as to be useless. It will suggest albums that are already in my library. Albums that I listened to a mere hours before. Thanks? I’m pretty aware of those. It will suggest groups of albums in sections as generic as “Indie.” Wow, how interesting! I had not heard of this “Indie” before! Where else could I find this genre?&lt;/p&gt;
&lt;p&gt;My favorite piece of the recommendation engine is new music. It is both incredibly timely and aloof at the same time. I am charmed by it. An artist that I listened to a couple of times will get a push notification, show up in recommendations, get a spot on the auto-generated New Music Mix playlist. However, a new song from Carly Rae Jepsen, one of my favorite artists? Never heard of her. Huh, we don’t seem to have—oh, wait, there it is, on her artist profile. She’s lucky I’m a big fan.&lt;/p&gt;
&lt;p&gt;When I have used Spotify previously, I found their recommendations to be fantastic. I could just turn on music and enjoy it. Find a vibe and follow it. It was great. Apple Music is basically manual. If I don’t pick it out, it’s not happening.&lt;/p&gt;
&lt;p&gt;On this point, it’s interesting that Apple struggles so much, as Apple Music is an area where they don’t have the same limitations around user data. Apple knows every song I’ve ever listened to. They know which albums I’ve hovered over, which artist pages I’ve routinely visited. They have my full iTunes purchase history. We go way back! Apple Music is the one place where they have a ridiculous amount of info about me, and they’re not using it. Well, they’re not using it to help &lt;em&gt;me&lt;/em&gt;, anyway.&lt;/p&gt;
&lt;h2&gt;Oh you want the album? Tap on the artist, dummy!&lt;/h2&gt;
&lt;p&gt;While you’re listening to a song, and you have the now playing view up, you can get to the song’s album by selecting the artist and then selecting “Go to Album.” You also have the option to open the artist’s page, which is the only action that makes sense when tapping on the artist.&lt;/p&gt;
&lt;h2&gt;Oh you want the lyrics? I thought you said “credits!”&lt;/h2&gt;
&lt;p&gt;On a Mac, you can open the three dot menu next to a song that’s currently playing, and then select “Get Info” to see the song’s lyrics, among other things. On iOS/iPadOS, you have to select “View Credits,” which then, inexplicably, includes a “View Lyrics” button. Love the priority of the artists, but I just want to know what Lady Gaga is saying. It’s “This kitten over here,” for the record.&lt;/p&gt;
&lt;h2&gt;Multi-device listening&lt;/h2&gt;
&lt;p&gt;I’m not even bothering with a silly headline. You know what I’m talking about. If I’m listening to a song on my computer and then pick up my phone and start listening to a song there, my computer pops up with a “More than one device...” warning with a button to “Upgrade.” Upgrade to a family plan. Not to a higher tier plan, the family plan. Great work everyone. I think we’re done here.&lt;/p&gt;
&lt;p&gt;At bare minimum, you should be able to transfer the currently playing song from one device to another. You can, allegedly, do this with a HomePod, which makes this even weirder. I know that Apple Music, the service, knows what I’m currently listening to. It knows to pop up the warning message!&lt;/p&gt;
&lt;h2&gt;Split albums&lt;/h2&gt;
&lt;p&gt;This drives me crazy. Albums in my library will randomly split apart, displaying the cover twice. Open one of them, and it will be a part of the album. And the rest will be in the duplicate. I have to delete both of the albums, search for it, and add it again to fix this. I haven’t found another way to do it. Which leads me into my next complaint…&lt;/p&gt;
&lt;h2&gt;Remove an album from the library, it removes the songs from all custom playlists&lt;/h2&gt;
&lt;p&gt;I’d like to speak to whoever thought this was a good idea. I need to know who hurt them. I need to speak to whoever hasn’t fixed this, or made it an option. If I delete an album from my library, it will also remove those songs from any custom playlist.&lt;/p&gt;
&lt;p&gt;I’ll often add an album to listen to it later, and then add songs that I particularly like to a playlist. Later, I will realize that I only really liked part of the album, so I’ll want to remove the album from my library. I could just leave it, yes! But I like to keep a refined list of albums that I actually like.&lt;/p&gt;
&lt;p&gt;To fix this, I’ll usually remove the album and then manually add the songs back to the playlist, and just hope I can get it all synced back up again.&lt;/p&gt;
&lt;p&gt;Back to the last point, sometimes I have to remove an album because it has split into two. Once I do that, the same problem happens where the songs are removed from playlists. I want to rip my hair out. These are software problems with software solutions, you’d think Apple could handle it. I wouldn’t recommend Apple Music to anyone I like.&lt;/p&gt;
</content:encoded></item><item><title>Build dynamic meta titles in Astro</title><link>https://samhermes.com/posts/build-dynamic-meta-titles-astro/</link><guid isPermaLink="true">https://samhermes.com/posts/build-dynamic-meta-titles-astro/</guid><pubDate>Sun, 07 Sep 2025 17:09:00 GMT</pubDate><content:encoded>&lt;p&gt;In Astro, you can create your meta tags in whatever way you’d like. It’s really freeform, so getting things set up exactly the way you’d like is rather manual. The difficulty can come from making customizations based on the page that is displaying.&lt;/p&gt;
&lt;p&gt;In the most basic case, let’s say that you want the site title to be the name of the homepage, and then on every other page you want the page title, a dash, and then the site title. This is something that you’d likely handle in the root layout file for your site, or in a &lt;code&gt;Head&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;You can get the page title from &lt;code&gt;Astro.props&lt;/code&gt;, which contains data about the current page. The current path can be retrieved from &lt;code&gt;Astro.url.pathname&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The path can be checked against the homepage path, which is &lt;code&gt;/&lt;/code&gt;. In this example, if it’s not the homepage, it inserts the page title and a dash, and then always adds the site title.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
const { title } = Astro.props;
const path = Astro.url.pathname;

const pageTitle = path !== &quot;/&quot; ? `${pageTitle} - ` : &quot;&quot;;
const metaTitle = `${pageTitle}Your Site Title Here`;
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that’s assembled, you can add the title to the page using the &lt;code&gt;title&lt;/code&gt; tag and the &lt;code&gt;metaTitle&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;title&amp;gt;{metaTitle}&amp;lt;/title&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve looked at ways that I could get the current collection to further refine the title, but there doesn’t seem to be a way to do that at a global level. For my case, I was able to manually add the collection name to the frontmatter of each markdown file, and then pass that to the global layout file for inclusion. Again, it&apos;s all a bit manual, it seems. Great for flexibility, but it would be nice if there was a little more structure here.&lt;/p&gt;
</content:encoded></item><item><title>Hello, Astro!</title><link>https://samhermes.com/posts/hello-astro/</link><guid isPermaLink="true">https://samhermes.com/posts/hello-astro/</guid><pubDate>Sun, 24 Aug 2025 17:51:00 GMT</pubDate><content:encoded>&lt;p&gt;My site is now running on the Astro framework. I’ve had my eye on Astro for a long time, and was looking for an excuse to use it. I finally realized that I could just use it for my own site! I assumed that I’d need to be in migration for a little while, and created a branch to handle the switch. However, it went so smoothly, I’m already done.&lt;/p&gt;
&lt;h2&gt;From Eleventy&lt;/h2&gt;
&lt;p&gt;My site previously ran on Eleventy, which I loved. For my purposes, the two frameworks are fairly similar. Also, they are both built with JavaScript, and so edge cases are handled in similar ways.&lt;/p&gt;
&lt;p&gt;Each framework also works off of “collections” of content, so setting up and handling groups of pages is very similar. I found Astro’s handling to be a little easier to work with, as collection content needs to be separate from the template. It made it easier to understand where to put everything.&lt;/p&gt;
&lt;h2&gt;It Just Works&lt;/h2&gt;
&lt;p&gt;I’m still marveling at the way that Astro is able to get markdown, HTML, and the special &lt;code&gt;.astro&lt;/code&gt; files to work together seamlessly. I have all of my posts stored in markdown, some of my landing pages have custom HTML. I could use &lt;code&gt;.astro&lt;/code&gt; files to mix layout files, extra HTML, and markdown content to build the final page. This also meant that I could import styles into specific pages as needed.&lt;/p&gt;
&lt;h2&gt;Use the Platform&lt;/h2&gt;
&lt;p&gt;I really enjoy working with Astro, as it feels like it’s working &lt;em&gt;with&lt;/em&gt; the web platform instead of against it. It’s written in JavaScript, but isn’t afraid of HTML. The best part is that after the site is built, it’s just HTML. It doesn’t require any JavaScript to run, and you can’t even tell that it was built with Astro.&lt;/p&gt;
&lt;p&gt;As I’ve worked with Next.js a lot, I was assuming that metadata would be a &lt;strong&gt;system&lt;/strong&gt;. I was delighted to find that I could simply set up meta tags in the root template and pass the data that I needed to them. I could customize and tweak in any way that I wanted.&lt;/p&gt;
&lt;h2&gt;Tags&lt;/h2&gt;
&lt;p&gt;One of the hardest things to figure out when I was setting up Eleventy was tag archive pages. In fact, I just gave up on it for a while. They aren’t super important to me, so it wasn’t a big deal.&lt;/p&gt;
&lt;p&gt;At first, it appeared that I was going to have the same issues with Astro. The docs seemed pretty light on the topic, but then I found that they had a whole section devoted to building a blog, with a &lt;a href=&quot;https://docs.astro.build/en/tutorial/5-astro-api/2/&quot;&gt;tutorial on tag pages&lt;/a&gt;. Excellent! This helped me get them up and running pretty quickly. I ran into some issues with capitalization, but that’s for another day.&lt;/p&gt;
</content:encoded></item><item><title>The broken trust of the back button</title><link>https://samhermes.com/posts/broken-trust-back-button/</link><guid isPermaLink="true">https://samhermes.com/posts/broken-trust-back-button/</guid><pubDate>Sun, 20 Jul 2025 17:46:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the worst user experience offenses caused by the &lt;a href=&quot;https://infrequently.org/series/reckoning/&quot;&gt;JavaScript-ification&lt;/a&gt; of the web is a broken back button. In this environment, it’s &lt;em&gt;not&lt;/em&gt; the browser that fails to take the user back, it’s that developers have taken over control of what “back” means and how it behaves. When it fails, it’s often that either the history state gets messed up, or the previous state wasn&apos;t ever entered into the history state.&lt;/p&gt;
&lt;p&gt;As a user, the most common instance of this happening is on e-commerce sites. Choose a product category, apply some filters, go to the second page of results, and then choose a product. Once there, you might change your mind, click on the back button, and you have no idea if you’ll land back where you were, or be taken back to the start with no filters or pagination applied.&lt;/p&gt;
&lt;p&gt;I don’t understand why we’ve so willingly tossed out this basic functionality. Yes, we’ve had our reasons for using more JavaScript, but maintaining the basic functions of the browser is a base level expectation. We are creating a world in which users avoid the back button, assuming that it won’t behave as they want. Or they go ahead and use it, and end up frustrated that they’ve once again lost their place.&lt;/p&gt;
&lt;p&gt;This quote from &lt;a href=&quot;https://unplannedobsolescence.com/blog/hard-page-load/&quot;&gt;Who&apos;s Afraid of a Hard Page Load?&lt;/a&gt; by Alexander Petros illustrates this experience clearly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If it’s an SPA, however, in all likelihood clicking the back button will take me a different, mostly blank page, and now I’m just stuck. When the internet comes back, I’ll refresh the page and hopefully land in the same place, but maybe not. In fact, my whole attitude towards a website changes if it feels like an SPA. Subconsciously, I know that I have to baby it, and only use it in the most optimal network conditions. The smoothness of a web application is an anti-indicator of its reliability and predictability as a web page.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Building products that behave consistently as expected builds trust with users. We, as a web industry, are eroding this trust on a massive scale. One way that we begin to fix this is to rely less on JavaScript for routing. If each “view” of a site is independently available, this ensures that a user has something to go back to. This means filters need to have unique URLs, paginated lists need to exist outside of a “load more” experience, and things like dialogs are only used for temporary controls or messaging. If that means we have to use much less JavaScript, all the better.&lt;/p&gt;
</content:encoded></item><item><title>Creating the Scroll Snap Controls package</title><link>https://samhermes.com/posts/creating-the-scroll-snap-controls-package/</link><guid isPermaLink="true">https://samhermes.com/posts/creating-the-scroll-snap-controls-package/</guid><pubDate>Sat, 17 May 2025 17:15:00 GMT</pubDate><content:encoded>&lt;p&gt;I just released the first version of a new package, &lt;a href=&quot;https://github.com/samhermes/scroll-snap-controls&quot;&gt;Scroll Snap Controls&lt;/a&gt;. It’s fairly simple, adding next and previous buttons to a container that uses CSS scroll snap. This allows us to provide a neat and tidy layout, shared between mobile and desktop, and still reach users without a way to horizontally scroll.&lt;/p&gt;
&lt;p&gt;The package is designed for use with elements that horizontally scroll. In order to activate this, we need to use &lt;code&gt;overflow&lt;/code&gt;. Even without using scroll snap, this can make it more difficult for users to access overflowed content. This is why we need to add our own navigation buttons to let them click to go back and forth.&lt;/p&gt;
&lt;p&gt;While working on this, I learned about the emerging &lt;code&gt;::scroll-button()&lt;/code&gt; spec (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::scroll-button&quot;&gt;MDN&lt;/a&gt;). At the moment, this is only available in Blink-based browsers, but if support expands, it will essentially make this package unnecessary. Woo CSS!&lt;/p&gt;
&lt;h2&gt;Class vs function&lt;/h2&gt;
&lt;p&gt;I wanted to build this code in a way that would be super flexible, allowing it to be used in a variety of contexts. I also didn’t want to overdo it, as there are already a lot of good options out there for more advanced implementations.&lt;/p&gt;
&lt;p&gt;I wrestled at first with how to structure the code. The first version I created used a class-based approach, neatly nesting all of the related functions inside. When attempting to use it in a demo, it felt like a little too much structure for my taste.&lt;/p&gt;
&lt;p&gt;I ended up just creating a series of functions and bringing them together with an &lt;code&gt;init&lt;/code&gt; function that I exported as the default. Modules are now widely supported, so it made sense to keep things simple.&lt;/p&gt;
&lt;h2&gt;Modules&lt;/h2&gt;
&lt;p&gt;Working with a simple HTML document to work on the functionality of the plugin is an easy way to get started, but I found that I wanted to convert the code to a module. This doesn’t work when you just load a local file in your browser. I deployed the code to a hosted environment and continued working from there.&lt;/p&gt;
&lt;p&gt;To use code as a module, it’s as simple as adding &lt;code&gt;type=“module”&lt;/code&gt; to the &lt;code&gt;script&lt;/code&gt; tag. This allows you to use &lt;code&gt;import&lt;/code&gt; and other features inside of the code. For my demo page, I imported the script from the parent directory, and it works the same as when imported from a package.&lt;/p&gt;
&lt;h2&gt;Creating a package&lt;/h2&gt;
&lt;p&gt;I’ve only made the code available on GitHub. npm maintains a way to install GitHub repositories as a package using the &lt;code&gt;&amp;lt;username&amp;gt;/&amp;lt;repo-name&amp;gt;#&amp;lt;version&amp;gt;&lt;/code&gt; format.&lt;/p&gt;
&lt;p&gt;In order for this to work, the repository does need a &lt;code&gt;package.json&lt;/code&gt; file. This tells npm about the code and, most importantly, which file is the entry point. I only had one file, so I set this to &lt;code&gt;index.js&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;CSS to the rescue&lt;/h2&gt;
&lt;p&gt;As previously mentioned, around the time I started working on this, I read about an initiative to bring these kinds of controls to CSS. It’s part of a new overflow spec, which focuses on adding navigation overflow elements. The main example is the &lt;a href=&quot;https://developer.chrome.com/blog/carousels-with-css&quot;&gt;classic carousel&lt;/a&gt;, with next and previous buttons and pagination controls.&lt;/p&gt;
&lt;p&gt;It’s really exciting to see this being worked on, especially for the enhanced accessibility that this will offer out of the box. It appears that this implementation will be really flexible, and I’m looking forward to trying these in out in real world use cases.&lt;/p&gt;
&lt;h2&gt;This is all really confusing&lt;/h2&gt;
&lt;p&gt;Creating code in this sort of public-facing way is really confusing! How do people want to use this code? What should be supported? CommonJS or ES-something? Can I just leave it on GitHub or is it better to get it on npm? Why is getting something on npm so difficult? It’s all so flexible and open that it’s hard to know what the cow paths are. What do people do most often? I’m not sure.&lt;/p&gt;
&lt;p&gt;As an attempt to learn more about what’s commonly done, I read &lt;a href=&quot;https://www.totaltypescript.com/how-to-create-an-npm-package&quot;&gt;this article from Total Typescript about creating a package&lt;/a&gt;, and it’s sooo long! Oh my gosh! Especially for something that’s really small like the package I was working on, the effort is not worth it. I just left my code on GitHub, and I’ll come back to npm later.&lt;/p&gt;
</content:encoded></item><item><title>Implementing media controls in custom blocks, revisited</title><link>https://samhermes.com/posts/implementing-media-controls-custom-blocks-revisited/</link><guid isPermaLink="true">https://samhermes.com/posts/implementing-media-controls-custom-blocks-revisited/</guid><pubDate>Sun, 16 Feb 2025 18:52:00 GMT</pubDate><content:encoded>&lt;p&gt;I last &lt;a href=&quot;https://samhermes.com/posts/implementing-media-controls-in-custom-blocks&quot;&gt;wrote about this topic in 2019&lt;/a&gt;, and, well, not a lot has changed since then. However, I left a list of questions at the end of that post, and never returned to answer them. Let’s take a look in a wholistic way, answering those questions along the way.&lt;/p&gt;
&lt;h2&gt;Add block attributes&lt;/h2&gt;
&lt;p&gt;In the block.json file, we want to add at least one new attribute for storing the media file’s ID. Previously, I was storing the URL of the large image size, but that was fragile and made evolving the block over time more difficult. Additionally, the &lt;code&gt;&amp;lt;MediaUpload&amp;gt;&lt;/code&gt; component needs an ID for the &lt;code&gt;value&lt;/code&gt; prop, which shows the currently selected image to the user in the media modal. This is useful for cases where someone wants to switch the currently selected image.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;attributes&quot;: {
  ...
  &quot;mediaId&quot;: {
    &quot;type&quot;: &quot;number&quot;,
    &quot;default&quot;: 0
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re using &lt;code&gt;render.php&lt;/code&gt; to display the image on the front end, you could get by with only &lt;code&gt;mediaId&lt;/code&gt;. In the event that you’re using the &lt;code&gt;save&lt;/code&gt; function, you’ll want to store a few more image attributes. If you’re using the image as a background image, you’ll need an attribute for the image URL. If you’re using an image tag, you’ll also want to store the image alt attribute.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;attributes&quot;: {
  ...
  &quot;mediaURL&quot;: {
    &quot;type&quot;: &quot;string&quot;
  },
  &quot;mediaAlt&quot;: {
    &quot;type&quot;: &quot;string&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Add components to Edit function&lt;/h2&gt;
&lt;p&gt;There are a number of components that you could use to add media controls to a block, and quite a few components available from third parties. WordPress provides &lt;code&gt;MediaPlaceholder&lt;/code&gt; and &lt;code&gt;MediaUpload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Import them like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { MediaPlaceholder, MediaUpload } from &apos;@wordpress/block-editor&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The placeholder component is great for prompting a user to upload or select an image, and once they’ve done that, we can display the image in its place.&lt;/p&gt;
&lt;p&gt;This component could be placed in the main content area, or you could add it to the block settings panel in the sidebar. It just depends on what’s appropriate for your block. The functionality remains the same.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{mediaId ? (
  // If an image has been selected, display here using mediaUrl
) : (
  &amp;lt;MediaPlaceholder
    onSelect={onSelectMedia}
    allowedTypes={[&apos;image&apos;]}
  /&amp;gt;
)}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, this component can accept images, videos, or audio files, so this limits it down to just images as well.&lt;/p&gt;
&lt;h2&gt;Handling the onSelect callback&lt;/h2&gt;
&lt;p&gt;To use the MediaPlaceholder component, we need to handle what happens when a user selects an image. To do this, we can pass a function in to the &lt;code&gt;onSelect&lt;/code&gt; prop of the placeholder. &lt;a href=&quot;https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/src/components/media-placeholder/README.md#onselect&quot;&gt;It will give you the media object&lt;/a&gt;, so it’s pretty easy to take those values and store them in the block attributes. Here, we just take the media file’s ID and store it in the &lt;code&gt;mediaId&lt;/code&gt; attribute we previously created.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const onSelectMedia = (media) =&amp;gt; {
  setAttributes({
    mediaId: media.id,
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Optional: Store the image’s URL in block attributes&lt;/h2&gt;
&lt;p&gt;In my previous version of this post, I was using lodash to retrieve the image URL and storing that in block attributes. At the time, I wasn’t aware of just how little lodash’s &lt;code&gt;get()&lt;/code&gt; function was doing. All we really need is a question mark. Multiple question marks. Poetic.&lt;/p&gt;
&lt;p&gt;Inside the &lt;code&gt;onSelectMedia&lt;/code&gt; function above, we can log out the details of the media file to get a better look at what WordPress is giving us.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(media);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Build the block, reload the page, select a new image, and pop open the developer console. There, you’ll find a rather large amount of data about the image. We can conditionally pull any of this and store it in the block’s attributes. Or, access directly inside the block (more on that below).&lt;/p&gt;
&lt;p&gt;If we want to get the &lt;code&gt;large&lt;/code&gt; image size, we could check for its existence and save it to a variable if it exists, falling back to the full size if not. As these values get pretty nested, we need to check for the existence of each layer using &lt;code&gt;?&lt;/code&gt; after each. This replaces the functionality of the &lt;code&gt;get()&lt;/code&gt; function from lodash.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const src =
  media.sizes?.large?.url ||
  media.media_details?.sizes?.large?.source_url ||
  media.url;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could then update the &lt;code&gt;setAttributes&lt;/code&gt; function to store that value:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;setAttributes({
  mediaId: media.id,
  mediaUrl: src,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Optional: Add control for removing or updating image&lt;/h2&gt;
&lt;p&gt;This will depend on your unique use case, but it’s helpful to allow a user to update the image in your block after they’ve set it. There are a number of ways to go about this. In the previous version of this post, I suggested &lt;a href=&quot;https://samhermes.com/posts/implementing-media-controls-in-custom-blocks/&quot;&gt;adding a control to the block toolbar&lt;/a&gt;. You could also add this control in the main edit area of the block, or in the block settings sidebar.&lt;/p&gt;
&lt;p&gt;In whatever way you implement this, the component that you’ll use is &lt;code&gt;&amp;lt;MediaUpload&amp;gt;&lt;/code&gt;. This component works just like the &lt;code&gt;&amp;lt;MediaPlaceholder&amp;gt;&lt;/code&gt; component, but allows you to define a &lt;code&gt;render&lt;/code&gt; function, meaning you can create any UI that you’d like. You could use the &lt;code&gt;IconButton&lt;/code&gt; component from WordPress in the toolbar, or the &lt;code&gt;Button&lt;/code&gt; component in the sidebar.&lt;/p&gt;
&lt;p&gt;To remove the image, you could call &lt;code&gt;setAttributes&lt;/code&gt; and set the &lt;code&gt;mediaId&lt;/code&gt; to zero. Or, to update, you could hook the &lt;code&gt;&amp;lt;MediaUpload&amp;gt;&lt;/code&gt; component to the same &lt;code&gt;onSelectMedia&lt;/code&gt; callback as before using the &lt;code&gt;onSelect&lt;/code&gt; prop. The remove and edit buttons will need to be separate in the UI, and this generally makes more sense for a user. The media modal from WordPress doesn’t allow for the removal of a selection.&lt;/p&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;Here’s the entire Edit function that we’ve created, with just the media controls. You’re like to have other controls mixed in here, but I’ve pulled this back for better understanding:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useBlockProps, MediaPlaceholder, MediaUpload } from &apos;@wordpress/block-editor&apos;;

export default function Edit({
  attributes: {
    mediaId,
    mediaUrl,
    mediaAlt,
  },
  setAttributes,
}) {
  const onSelectMedia = (media) =&amp;gt; {
    const src =
      media.sizes?.large?.url ||
      media.media_details?.sizes?.large?.source_url ||
      media.url;

    setAttributes({
      mediaId: media.id,
      mediaUrl: src,
      mediaAlt: media.alt
    });
  };

  return (
    &amp;lt;div {...useBlockProps()}&amp;gt;
      {mediaUrl ? (
        // If an image has been selected, display here
      ) : (
        &amp;lt;MediaPlaceholder
          onSelect={onSelectMedia}
          allowedTypes={[&apos;image&apos;]}
        /&amp;gt;
      )}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Get page content for posts page in WordPress</title><link>https://samhermes.com/posts/get-page-content-posts-page-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/get-page-content-posts-page-wordpress/</guid><pubDate>Sun, 03 Nov 2024 17:41:00 GMT</pubDate><content:encoded>&lt;p&gt;In WordPress, you can set your homepage to either display a list of the latest posts or a static page. When the static page option is used, you can additionally select a second page on which to display the list of the latest posts. Of course, to select this page, you’ll need to have created a page that you’d like to use. This page will be overtaken by the list of the latest posts, so any content that you add to the page will not be displayed.&lt;/p&gt;
&lt;p&gt;In the event that you’d like to show that page’s content in addition to the list of posts, you can fetch the content using the page ID. Here, the page ID is retrieved using &lt;code&gt;get_option()&lt;/code&gt; to get the page currently assigned as the posts page, and then the ID is used to get the page content using &lt;code&gt;apply_filters()&lt;/code&gt;. Optionally, the current page number could be stored in a variable for later use.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Optional - used for showing the content on just the first page
$current_page = get_query_var( &apos;paged&apos; ) ? get_query_var( &apos;paged&apos; ) : 1;
$page_for_posts = get_option( &apos;page_for_posts&apos; );
$posts_page_content = apply_filters( &apos;the_content&apos;, get_the_content( null, false, $page_for_posts ) );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, at the spot in the template where you’d like to display the content, use &lt;code&gt;wp_kses_post()&lt;/code&gt; to output the variable. Here, a check is performed for the existence of the content (in case there is no content on the page), and then a check to see if this is the first page of results. As most users will land on the first page, we can assume that they’ve already read the content and skip it on the second page, where they are likely just browsing the posts.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if ( $posts_page_content &amp;amp;&amp;amp; $current_page === 1 ) {
  echo &apos;&amp;lt;div class=&quot;page-content&quot;&amp;gt;&apos; . wp_kses_post( $posts_page_content ) . &apos;&amp;lt;/div&amp;gt;&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>What makes a website feel native?</title><link>https://samhermes.com/posts/what-makes-website-feel-native/</link><guid isPermaLink="true">https://samhermes.com/posts/what-makes-website-feel-native/</guid><pubDate>Sun, 25 Aug 2024 19:17:00 GMT</pubDate><content:encoded>&lt;p&gt;There are a lot of pieces that go into making a good website. The design, the content, the UX. Each of these need to come together in harmony to meet users where they are. The piece of this that I&apos;m most interested in, naturally, is the front end development part. This is really where all of the other disciplines meet, and can really make or break a site. To this end, I think that it&apos;s a sense of a site feeling &quot;native&quot; that measures how successful it is. So, what makes a website native?&lt;/p&gt;
&lt;p&gt;In general, what &quot;native&quot; means in this context is in browser. Is the site working with the browser or against it. Of course, the browser is forgiving, and very backwards compatible, so &quot;native&quot; does have a recency about it. It&apos;s about taking advantage of the new features that are widely supported, while also respecting the basics.&lt;/p&gt;
&lt;h2&gt;Navigation&lt;/h2&gt;
&lt;p&gt;A native website should take full advantage of the browser&apos;s navigation tools. Using the back and forward buttons should go back and forward. Opening a link in a new tab or window should open the expected page.&lt;/p&gt;
&lt;p&gt;Too often, single page apps break the back and forward actions. The history state can easily be messed up, causing a user to lose their place. Typically, serving pages from the server is a better bet.&lt;/p&gt;
&lt;h2&gt;Pixel independent&lt;/h2&gt;
&lt;p&gt;We now live a world with a great variety of pixel density screens. Part of making a website feel native is to serve the right quality of graphic to the right screen. Responsive images help a great deal with this, allowing the user to only download the highest quality graphic that their screen supports.&lt;/p&gt;
&lt;p&gt;I love using SVGs to simplify this problem, at least as far as vector graphics go. A single asset will display as crisp as possible on any screen, and can be made to be really small. Additionally, we can adjust the colors in the SVG using CSS, so a single file can support light and dark mode, or cases where it should appear on a dark background in one part of the page and on a light background in another.&lt;/p&gt;
&lt;h2&gt;Smooth animations&lt;/h2&gt;
&lt;p&gt;Browsers have very real limitations on performance, and for good reason. An expensive animation can use a lot of resources, so understanding what those limits are can keep an animation smooth.&lt;/p&gt;
&lt;p&gt;The most difficult part of this one is the great variability in resources. A lower powered device needs to play the same animations as a higher power device. In general, this means that you&apos;ll likely need to get creative, or settle for a less complex animation. If you&apos;ve visited apple.com before, you&apos;ll know what happens when you don&apos;t settle.&lt;/p&gt;
&lt;h2&gt;Accessible&lt;/h2&gt;
&lt;p&gt;An accessible website uses the platform properly, so a native website is using good markup, the styles aren&apos;t getting in the way, and JavaScript has considered screen reader usage.&lt;/p&gt;
&lt;h2&gt;Responsive&lt;/h2&gt;
&lt;p&gt;An obvious entry, but it&apos;s important to remember that the user&apos;s viewport can be any size. The possibilities are astounding. The layout of the website should adapt to all of those. Some websites are obviously designed for just &quot;mobile&quot; and &quot;desktop,&quot; and not much else. Using one of these sites on a tablet can be difficult. If on a tablet, the site is serving up a mobile layout, it&apos;s likely that space isn&apos;t being used very well, and font sizes are likely too small.&lt;/p&gt;
&lt;p&gt;To feel native, we should think about how best to support the spectrum of screen sizes. Using a series of breakpoints works great for this, or we can take advantage of dynamic units, like &lt;code&gt;vh&lt;/code&gt;, &lt;code&gt;ch&lt;/code&gt;, or percentages.&lt;/p&gt;
&lt;h2&gt;Easily shareable&lt;/h2&gt;
&lt;p&gt;Me, talking about sharing things? More likely than you think. This really connects back into the JavaScript of it all. Is there a way to share an individual piece of content? Can the user get to a place where they can share just what they want to share? In a single page app, this can go sideways easily, where the share link just takes someone to the start of the app, or to the entire page.&lt;/p&gt;
&lt;h2&gt;Familiar&lt;/h2&gt;
&lt;p&gt;Last but not least, does the website use familiar patterns? This one is much harder to define, because it&apos;s quite social. What one person finds familiar isn&apos;t what another does. However, if we use common patterns that are used by many websites, we have a greater sense of a website feeling native. Unusual interactions can throw users off, and make it feel like a website is bad.&lt;/p&gt;
</content:encoded></item><item><title>The tension between modularity and accessibility</title><link>https://samhermes.com/posts/tension-between-modularity-accessibility/</link><guid isPermaLink="true">https://samhermes.com/posts/tension-between-modularity-accessibility/</guid><pubDate>Sat, 10 Aug 2024 17:45:00 GMT</pubDate><content:encoded>&lt;p&gt;Modularity is everywhere. It&apos;s React components. It&apos;s packages. It&apos;s WordPress blocks. The web has been fully modularized. I&apos;ve done my fair share of adding to this, and while it&apos;s really good for organizing code and for project management, it can often be detrimental for users. Especially when used in places where it isn&apos;t really needed.&lt;/p&gt;
&lt;p&gt;External dependencies often make this problem even worse. When we bring in a package because we need a feature, we&apos;re also reliant on the accessibility of that code. Often, the functionality that we&apos;re after is so tightly coupled with the markup and styles that are provided, it can be impossible to work around it.&lt;/p&gt;
&lt;h2&gt;Accessibility is about context&lt;/h2&gt;
&lt;p&gt;In order to improve accessibility, we often need to be adaptable based on context. In the simplest case, this is about what markup we use. It could be heading level, wrapping element, even IDs. Taking a modular approach, it can be really difficult to be adaptable based on context. It might require extra properties on a component, or additional variations.&lt;/p&gt;
&lt;p&gt;If I create a card component, I&apos;ll likely choose a &lt;code&gt;div&lt;/code&gt; to wrap it. I&apos;ll usually pick a &lt;code&gt;h2&lt;/code&gt; for the heading. These both work pretty good for most cases. However, if there are many cards in a group, it would be better to wrap the card in a &lt;code&gt;li&lt;/code&gt; as part of a &lt;code&gt;ul&lt;/code&gt;. Additionally, that group of cards could be one of many groups, each with a heading. In that case, we should use a &lt;code&gt;h3&lt;/code&gt; in each card. Suddenly, this simple component is getting complicated.&lt;/p&gt;
&lt;h2&gt;Accessibility is about the page as a whole&lt;/h2&gt;
&lt;p&gt;Accessibility requires that you orchestrate coordination between components, which is more difficult in a modular approach. If one component should close when another opens, or a focus state should be passed from one component to another on an event, it requires hoisting behavior up really high in the tree, or concocting complex logic in each component.&lt;/p&gt;
&lt;p&gt;In vanilla JS, it&apos;s much easier to apply these page-wide updates. This can be seen as &quot;wrong&quot; or &quot;unsafe,&quot; but many websites are not so complicated that they benefit from completely avoiding whatever dangers may lurk.&lt;/p&gt;
&lt;h2&gt;Accessibility should be easy&lt;/h2&gt;
&lt;p&gt;The reason that I make this argument is that it feels that we are headed in a direction where it&apos;s harder than before to make accessible websites. We should be headed in the opposite direction, where accessibility happens easily, almost without even thinking about it.&lt;/p&gt;
&lt;p&gt;If our modular tools evolve to more easily enable accessibility, then that&apos;s great. I don&apos;t see that happening though, as modularity usually comes alongside a more strict environment, so it would go against the nature of the approach.&lt;/p&gt;
&lt;h2&gt;What to do instead&lt;/h2&gt;
&lt;p&gt;The web is a messy platform. Our job as developers is to handle that messiness, allow things to be tightly coupled. If the end product is accessible, that&apos;s the real goal. If our code is perfectly clean and orderly, it&apos;s really likely that it&apos;s been at the sacrifice of a user. That&apos;s just the nature of this imperfect platform.&lt;/p&gt;
&lt;p&gt;What&apos;s most important is to get closer to the platform again. Get closer to HTML and CSS, and make sure that you understand what is being served to the user. Test code thoroughly. Start your work with the end markup and add functionality on top of it. Add comments to your code where it gets to be complex.&lt;/p&gt;
&lt;p&gt;I prefer to have a set of helper functions and starter components to use and adapt on a per-project basis. Of course, with a deadline, we often need something to start with quickly, but we should be okay with customizing and creating one-offs. Wait to modularize until you&apos;re sure you need it.&lt;/p&gt;
</content:encoded></item><item><title>Halle 1.2.0 Released</title><link>https://samhermes.com/posts/halle-120-released/</link><guid isPermaLink="true">https://samhermes.com/posts/halle-120-released/</guid><pubDate>Sun, 07 Jul 2024 23:55:00 GMT</pubDate><content:encoded>&lt;p&gt;A couple of weeks ago, I pushed out an update to my WordPress theme &lt;a href=&quot;https://wordpress.org/themes/halle&quot;&gt;Halle&lt;/a&gt;. I hadn&apos;t updated it in a long time, so it was overdue. WordPress had added a banner on the listing, warning that it had been more than 2 years since an update. It was still running just fine, but you know, tech industry and all.&lt;/p&gt;
&lt;p&gt;I know that I&apos;m &quot;supposed&quot; to test the theme with each major WordPress release and update the &quot;Tested up to:&quot; value on the theme, but I really don&apos;t have the time or energy to do that. Plus, nothing has broken so far? What&apos;s the point?&lt;/p&gt;
&lt;p&gt;The main purpose of the update was to offer a new layout option for single posts. The original design had used a fixed sidebar, and so it really wasn&apos;t possible to use wide or full width blocks. I added the full width layout as an option that needs to be toggled on. It applies to all posts, so someone would need to commit to that layout on all existing and new posts.&lt;/p&gt;
&lt;p&gt;Pushing out these updates, I questioned a lot, so I wanted to work through those a little.&lt;/p&gt;
&lt;h2&gt;Does anyone use the theme?&lt;/h2&gt;
&lt;p&gt;There isn&apos;t a way to know how many sites are actually making use of a theme from the official theme directory. It gives a public status of how many &quot;active installations&quot; there are. I don&apos;t have any additional information as the theme author, even if I log in.&lt;/p&gt;
&lt;p&gt;Currently, Halle has &quot;100+ active installations.&quot; I&apos;m not really sure what to do with that information. What makes an installation &quot;active?&quot; Are any of those installations actually using the theme on a real site? As far as I can tell, no one is actually using the theme.&lt;/p&gt;
&lt;p&gt;If there was a way to know exactly which sites were using the theme, it would be sort of overwhelming because I would want to look at them and see if there was anything that could be improved. In a way, it&apos;s nice to not know. Still, it feels a bit like a shot in the dark to push out an update.&lt;/p&gt;
&lt;h2&gt;Theme screenshots&lt;/h2&gt;
&lt;p&gt;As part of the update, I wanted to add some additional screenshots to the theme. With the new post layout option, I thought that it would be nice to show the two layouts, to give a visual comparison. This doesn&apos;t appear to be available to themes anymore? I&apos;m questioning if it was ever an option. I tried to find information about how to do it, but everything was older. I tried to find where this option was removed, but couldn&apos;t find anything. It&apos;s possible that I confused this with plugin screenshots, which are still an option.&lt;/p&gt;
&lt;p&gt;It seems like additional screenshots would be really useful for a theme. The &quot;live preview&quot; that the theme directory offers is really disappointing, so there&apos;s hardly a way to know what a theme will look like without installing it first.&lt;/p&gt;
&lt;h2&gt;Converting to a block theme&lt;/h2&gt;
&lt;p&gt;Halle is technically a &quot;classic&quot; theme now (still annoyed at this). It makes me wonder if there&apos;s a way to convert it to a block theme. There doesn&apos;t appear to be a way to do this at the moment. The theme relies on some settings in the Customizer, which wouldn&apos;t transfer. So, if someone installed the &quot;block theme&quot; update, they&apos;d need to set everything up again.&lt;/p&gt;
&lt;p&gt;Additionally, if I were to convert it to a block theme, I&apos;m not sure what the advantage would be to the end user. They would have slightly more flexibility in the header of the theme. Doing this would be much more complex than what is there, and I&apos;m not sure there&apos;d be any payoff. The footer is already very flexible. It makes use of a sidebar area, so it&apos;s using blocks already.&lt;/p&gt;
&lt;p&gt;So, does this mean that classic themes should just be left for dead? Should I abandon the project at this point? Do I just have to start over, and submit a new block theme? Has this whole thing been for nothing?&lt;/p&gt;
&lt;p&gt;I learned a lot from making a theme for the official repository, but it&apos;s really disappointing and I wouldn&apos;t really recommend it to anyone else.&lt;/p&gt;
</content:encoded></item><item><title>Add GitHub repository as npm dependency</title><link>https://samhermes.com/posts/add-github-repository-npm-dependency/</link><guid isPermaLink="true">https://samhermes.com/posts/add-github-repository-npm-dependency/</guid><pubDate>Thu, 11 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have a GitHub repository that contains foundational styles and scripts that I use in other projects. In order to avoid copying and pasting the code, I wanted to include it as an npm dependency. Additionally, I wanted to see if I could avoid sending it to npm, and get it directly from GitHub. Fortunately, you can!&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://docs.npmjs.com/cli/v9/commands/npm-install&quot;&gt;NPM docs on &lt;code&gt;npm install&lt;/code&gt;&lt;/a&gt;, GitHub repositories can be installed directly by using the [username]/[repository-name] convention:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install samhermes/alexander
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that runs, it will show up in package.json as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;dependencies&quot;: {
  &quot;alexander&quot;: &quot;github:samhermes/alexander&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This worked great, but then I started to wonder about versioning. If I make an update to the &lt;code&gt;alexander&lt;/code&gt; repository, the latest version will always be pulled into my projects when doing an install. In most cases, this would be a good thing, but it would be better to be able to opt in.&lt;/p&gt;
&lt;p&gt;Again, from the &lt;a href=&quot;https://docs.npmjs.com/cli/v9/commands/npm-install&quot;&gt;&lt;code&gt;npm install&lt;/code&gt; docs&lt;/a&gt;, I found that I could install based on a commit number or tag. I set up a tag for the latest version of the repository, and used it to reinstall:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install samhermes/alexander#1.0.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, package.json reflected the tagged version, and I&apos;ll need to update to a new version to get any future changes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;dependencies&quot;: {
  &quot;alexander&quot;: &quot;github:samhermes/alexander#1.0.3&quot;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Customize default wp-scripts config</title><link>https://samhermes.com/posts/customize-default-wp-scripts-config/</link><guid isPermaLink="true">https://samhermes.com/posts/customize-default-wp-scripts-config/</guid><pubDate>Thu, 28 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/&quot;&gt;&lt;code&gt;wp-scripts&lt;/code&gt;&lt;/a&gt; is a great package for building WordPress blocks, as it takes care of the basic build tooling out of the box, getting block development going quickly. However, while using it, I quickly found myself needing to customize the default configuration. For a while, I used some custom commands in the &lt;code&gt;scripts&lt;/code&gt; property of package.json, adding additional arguments, but eventually found that changing the config would offer more control.&lt;/p&gt;
&lt;p&gt;Fortunately, &lt;code&gt;wp-scripts&lt;/code&gt; is using webpack under the hood, and so this allows for modifications to be made using a project-specific webpack config. You can either wholesale replace the default config file, or selectively add on top of it. The approach that I took was to add on top of it.&lt;/p&gt;
&lt;p&gt;In my case, I wanted to add an additional &lt;a href=&quot;https://webpack.js.org/concepts/#entry&quot;&gt;entry&lt;/a&gt; for a slotfills file. In some cases, this could be handled in the default webpack config, but I needed to scope the slotfills to a specific post type, while leaving the blocks I&apos;d already created available to any post type.&lt;/p&gt;
&lt;p&gt;In order to add a custom config, I created a &lt;code&gt;webpack.config.js&lt;/code&gt; file in my project. In order to maintain the default config, you import it into your file from the &lt;code&gt;wp-scripts&lt;/code&gt; package, and then use that variable to apply the default as needed. In mine, I used it to first bring in the defaults for everything, and then brought in the default entries inside of the &lt;code&gt;entry&lt;/code&gt; object. The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax&quot;&gt;spread operator&lt;/a&gt; before the variable name brings in all elements of the default config.&lt;/p&gt;
&lt;p&gt;Once the default config is coming in, I added a new entry called &lt;code&gt;slotfills&lt;/code&gt;. Here&apos;s the entirety of the file from my project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const defaultConfig = require(&apos;@wordpress/scripts/config/webpack.config&apos;);
const { resolve } = require(&apos;path&apos;);

module.exports = {
  ...defaultConfig,
  entry: {
    ...defaultConfig.entry(),
    &apos;slotfills&apos;: resolve(
      process.cwd(),
      &apos;src/js/slotfills&apos;,
      &apos;index.js&apos;
    ),
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The great part of this is that I didn&apos;t need to do anything else. &lt;code&gt;wp-scripts&lt;/code&gt; immediately began picking up the new config, as webpack will check for a project level config file.&lt;/p&gt;
&lt;p&gt;For better visibility into exactly what this is adding to, you can view the &lt;a href=&quot;https://github.com/WordPress/gutenberg/blob/trunk/packages/scripts/config/webpack.config.js&quot;&gt;full default wp-scripts webpack config on GitHub&lt;/a&gt;. You can see why you might not want to do a wholesale replacement, as there&apos;s a lot there, and you likely want to be able to automatically receive updates with future versions.&lt;/p&gt;
&lt;p&gt;For more about setting up &lt;code&gt;wp-scripts&lt;/code&gt;, &lt;a href=&quot;https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/&quot;&gt;see this article on the WordPress dev site&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>How to use CSS container queries</title><link>https://samhermes.com/posts/how-to-use-css-container-queries/</link><guid isPermaLink="true">https://samhermes.com/posts/how-to-use-css-container-queries/</guid><pubDate>Sun, 30 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Of all the exciting things happening with CSS, I think container queries are at the top of the list for me. &lt;a href=&quot;https://caniuse.com/css-container-queries&quot;&gt;Browser support&lt;/a&gt; is really strong at this point, so while I&apos;d still exercise a bit of caution based on project context, we&apos;re entering the phase where we can seriously consider them without fallbacks.&lt;/p&gt;
&lt;h2&gt;What are they?&lt;/h2&gt;
&lt;p&gt;At a high level, container queries make it possible to create totally modularized, responsive components. The styles do not need to be aware of the current viewport width. We can define how we&apos;d like components to display or rearrange solely based on their container (as the name implies).&lt;/p&gt;
&lt;p&gt;The perfect example for this is a card component. With media queries, we have to tie the card&apos;s layout to the viewport width, which isn&apos;t very flexible if we want to use it in a variety of different places. With container queries, we could place the card in a two column layout, or in a sidebar, or at full width, and use the exact same markup and styles for it.&lt;/p&gt;
&lt;h2&gt;How do they relate to media queries?&lt;/h2&gt;
&lt;p&gt;In many cases, container queries can neatly replace media queries. Media queries become much more useful for overall page layout changes, and container queries are most powerful on a smaller scale.&lt;/p&gt;
&lt;h2&gt;How to use them&lt;/h2&gt;
&lt;p&gt;To start, container queries require that you define a &quot;containment context.&quot; Basically what you&apos;re doing is flipping the switch on an element to say that it is a container. By default, no element is a container, and this gives you control over which element is truly the outer element (or &quot;container&quot;) of a component. In an element with several nested elements, it would get complicated really quickly without the ability to specify which is the container.&lt;/p&gt;
&lt;h3&gt;Inline size vs size&lt;/h3&gt;
&lt;p&gt;When you define a containment context, you use the &lt;code&gt;container-type&lt;/code&gt; property and give it a value of either &lt;code&gt;inline-size&lt;/code&gt; or &lt;code&gt;size&lt;/code&gt;. This was confusing to me at first, as they seem really similar. What I&apos;ve found is that in most cases, &lt;code&gt;inline-size&lt;/code&gt; is what I would want to use. The default value for this property is &lt;code&gt;normal&lt;/code&gt;, in the event that you need to turn off a container.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container-element {
  container-type: inline-size;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Default usage&lt;/h3&gt;
&lt;p&gt;Once you&apos;ve set the containment context, you can use the new &lt;code&gt;@container&lt;/code&gt; on any of the elements inside of the container.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@container (min-width: 30em) {
  .child-element {
    font-size: 2rem;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Named containers&lt;/h3&gt;
&lt;p&gt;If you&apos;ve got a lot of containers, naming them is a nice way to clearly specify which container you&apos;re referring to. This isn&apos;t absolutely required, as it will target the nearest ancestor container by default. That could get confusing pretty quickly, so naming containers seems like a sensible default.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container-element {
  container-type: inline-size;
  container-name: card;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This could be shorthanded as &lt;code&gt;container: card / inline-size&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once you&apos;ve got it named, you can reference it directly in the query.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@container card (min-width: 50em) {
  .child-element {
    font-size: 3rem;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Container query length units&lt;/h3&gt;
&lt;p&gt;That rolls right off the tongue, doesn&apos;t it? These are really just some &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units&quot;&gt;new units&lt;/a&gt; that conceptually pair with the viewport units that we&apos;ve had for a little while. Instead of using the viewport to calculate their values, they use the current container. Helpful for font sizing and other dynamic sizing. I&apos;ve never gotten into using viewport units at a component level, as it&apos;s always felt a little too disconnected to me, but they make a lot more sense in the context of a container query.&lt;/p&gt;
&lt;h2&gt;Where to use them&lt;/h2&gt;
&lt;p&gt;The possibilities are really endless. It&apos;s obvious that these have been developed with the intention of maximum flexibility. I could see them taking over most media queries in any given project, from global components like navigation to small in-content components like callouts. I feel like this is bringing an end to the practice of having a defined list of breakpoints for a project and instead making definitions on a component level. As mentioned before, card components feel like the most immediately useful context for this, and the place I&apos;ll start.&lt;/p&gt;
</content:encoded></item><item><title>Slowly backing away from theme.json</title><link>https://samhermes.com/posts/slowly-backing-away-from-theme-json/</link><guid isPermaLink="true">https://samhermes.com/posts/slowly-backing-away-from-theme-json/</guid><pubDate>Thu, 25 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was on board with theme.json. I wrote a &lt;a href=&quot;https://samhermes.com/posts/getting-to-know-theme-json/&quot;&gt;whole post about it&lt;/a&gt; last year. However, I think I was confused. I thought that it was the future, where all roads lead. I’ve realized that it’s primarily meant for block themes, even though it isn’t presented this way. The &lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/&quot;&gt;top of the dev page about it&lt;/a&gt; reads “WordPress 5.8 comes with a new mechanism to configure the editor.” I took it at its word, and it hasn’t quite played out.&lt;/p&gt;
&lt;h2&gt;Injected styles&lt;/h2&gt;
&lt;p&gt;One of the first issues I ran into was with the styles that get added to the front end as soon as you add a theme.json file to your site (in a so-called “classic” theme). There are custom properties galore, but it also adds anything you set in the &lt;code&gt;styles&lt;/code&gt; part of theme.json. Adding theme.json to your theme sets the block editor’s font to “serif” for some reason. So, I set the font in theme.json, only to find that it also applies it to the front end. Next, I wanted to add some spacing the right and left of the block editor, as it is up against the viewport on mobile, but found that these were being applied to the body element on the front end. Attempting to change &lt;em&gt;just&lt;/em&gt; the editor is not possible, which is a shame when merely the presence of theme.json seems to cause issues.&lt;/p&gt;
&lt;p&gt;There is a way to disable these “global” styles, using &lt;code&gt;wp_dequeue_style( &apos;global-styles&apos; )&lt;/code&gt;, but this is wholesale. This is the frustrating part of losing control of things, as I &lt;em&gt;do&lt;/em&gt; want WordPress to manage some of these styles, because copying just what I want to my own theme is brittle.&lt;/p&gt;
&lt;h2&gt;Styles in JSON&lt;/h2&gt;
&lt;p&gt;Watching the further development of the site editor, I’ve seen instructions on how to add styles to theme.json to tweak the appearance of different blocks. This makes me uneasy, as it’s basically CSS in JS, which was a bad idea to begin with, and is fading in popularity already.&lt;/p&gt;
&lt;p&gt;There are quite a few issues here, the main one being the half-in half-out situation this leads to (as in some styles are coming from WordPress and some are coming from custom stylesheets in a theme). I see why it’s required for the block editor to work, and I see why they are putting equivalent styles on the front end, I just don’t see how someone might reasonably add their own styles on top. It feels too fragile to me.&lt;/p&gt;
&lt;p&gt;Specificity issues are already rampant since the block editor, and the constantly changing markup and class names only adds confusion and frustration.&lt;/p&gt;
&lt;h2&gt;PHP equivalent settings&lt;/h2&gt;
&lt;p&gt;For some of what theme.json offers control over, there is a PHP equivalent. You can set a color palette in PHP, disable font size settings, and things of that nature. While theme.json development is spurring ahead, there are some things that are not able to be controlled in PHP. This makes sense if all signs point to block themes, but ignores those sites using “classic” themes with the block editor. The need to tweak one single setting that isn’t available through PHP requires the addition of a theme.json file, causing all of the repercussions I mentioned above.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/#backward-compatibility-with-add_theme_support&quot;&gt;The short list of what is available through PHP is listed here.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;“Classic” themes&lt;/h2&gt;
&lt;p&gt;With the push towards the site editor and block themes, we have also been given the label of “classic” for all existing themes. Apparently everything that I’ve built for WordPress is now “classic.” Although this is just a label, it strongly suggests that everyone needs to be building block themes from here on out. The issue with this is that I haven’t seen a compelling reason to jump into block themes yet. It adds a huge amount of complexity with benefits that I don’t need. Not every user needs to be able to rearrange the site logo on a whim. I also do not want them to have that ability, as it makes styling that much harder.&lt;/p&gt;
&lt;p&gt;It’s funny to me that they are “classic” themes, as the same approach was taken with the “classic” editor plugin, and it’s &lt;a href=&quot;https://wordpress.org/plugins/browse/popular/&quot;&gt;still the fourth most popular plugin&lt;/a&gt;. Sometimes I wish that I was still holding on to it for dear life too.&lt;/p&gt;
&lt;p&gt;Ideally, there would be separation between how theme.json works with block themes and how it works with classic themes. It&apos;s attempting to solve for two different use cases at the moment.&lt;/p&gt;
&lt;h2&gt;Custom templates&lt;/h2&gt;
&lt;p&gt;Even in a classic theme, you can create a custom template? Using blocks? Even though you aren’t in a block theme? And then it overwrites the template from your theme just on that page? Bit of a loophole? I&apos;m assuming that this was unintentional and will be changed, but points to how uneven this implementation has been.&lt;/p&gt;
&lt;h2&gt;Developer relations&lt;/h2&gt;
&lt;p&gt;When Gutenberg came out, it was exciting and mysterious. There was so much to learn. It completely changed the way we build sites. It was also really bumpy. It changed all the time, it broke stuff, and, worst of all, it was poorly documented. We had to read the source code to figure out how it worked (and still do). A lot of the tension around the new editor was due to this, there was a lot to learn very quickly, and not too many ways to do it.&lt;/p&gt;
&lt;p&gt;It feels like we’re repeating the past with the site editor and block themes. It’s full steam ahead, and everyone will just have to figure it out for themselves after the fact.&lt;/p&gt;
&lt;p&gt;WordPress as a platform is a small slice of my stack. I use it heavily, but it’s not where I want to spend all my time. I just don’t have the space in the day to read every update or post about what has changed. Front-end developers are busy enough just trying to keep up with front-end things. The reality about the block editor and the site editor is that they both need a front-end developer to know them intimately to be able to use them successfully. It’s a lot to ask.&lt;/p&gt;
</content:encoded></item><item><title>Giving the dialog element a whirl</title><link>https://samhermes.com/posts/giving-the-dialog-element-a-whirl/</link><guid isPermaLink="true">https://samhermes.com/posts/giving-the-dialog-element-a-whirl/</guid><pubDate>Sat, 25 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After &lt;a href=&quot;https://www.scottohara.me/blog/2023/01/26/use-the-dialog-element.html&quot;&gt;Scott O’Hara’s suggestion to use the dialog element&lt;/a&gt;, I thought that it was time to try it out, see how it works, and what’s different or improved from the way I was approaching dialogs previously. To get yourself acquainted, here’s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog&quot;&gt;the MDN docs article about it&lt;/a&gt;. Additionally, if you’re looking for a quick, simplified demo, see &lt;a href=&quot;https://googlechrome.github.io/dialog-polyfill/&quot;&gt;this demo from Google&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Styling&lt;/h2&gt;
&lt;p&gt;My first reaction, naturally, was to the browser default styles. They are mostly the same across browsers. There’s a black border, a bit of padding, and positioning to center the element in the viewport. All of them are easy to adjust or remove, but it’s a little strange to have so much browser-default styling. It really suggests a more specific use of the element than is typical.&lt;/p&gt;
&lt;p&gt;For the display/hide functionality of the dialog, it uses the display property, and toggles it between &lt;code&gt;none&lt;/code&gt; and &lt;code&gt;block&lt;/code&gt;. This works, but means that we are limited on the amount of animation that we can use. &lt;code&gt;transition&lt;/code&gt; won’t work, so keyframe animations are needed, and we’re only able to animate the dialog in, not out, as &lt;code&gt;display: none&lt;/code&gt; will hide it immediately.&lt;/p&gt;
&lt;p&gt;Notably, if we attempt to handle the display state ourselves, such as by setting &lt;code&gt;display: block&lt;/code&gt; all of the time and replacing it with &lt;code&gt;visibility&lt;/code&gt;, we lose all of the accessibility features that are inherent in the element. So, that’s a bummer. &lt;a href=&quot;https://css-tricks.com/so-youd-like-to-animate-the-display-property/&quot;&gt;Maybe that will be a non-issue soon?&lt;/a&gt; 🤞 If you’re interested in getting around this in the meantime, I found &lt;a href=&quot;https://web.dev/building-a-dialog-component/&quot;&gt;this web.dev article&lt;/a&gt; to be a good example of how to approach that (though the author gets quite distracted by his CSS variable library).&lt;/p&gt;
&lt;p&gt;Additionally, when using the dialog in its modal state (more on that in a moment), it comes with a backdrop pseudo element that also comes with some browser-default styles. These are easy to adjust as well, though there is &lt;a href=&quot;https://kilianvalkhof.com/2023/css-html/backdrop-doesnt-inherit-from-anywhere/&quot;&gt;apparently a quirk where it doesn’t currently inherit anything&lt;/a&gt;, rendering your custom properties useless in its context.&lt;/p&gt;
&lt;h2&gt;Functionality&lt;/h2&gt;
&lt;p&gt;I had assumed that all of the functionality required to hide and show the dialog would need to be managed through JavaScript. As it turns out, not all of it does. It would be so cool if none of it did.&lt;/p&gt;
&lt;p&gt;If you insert a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element into the dialog, with a &lt;code&gt;method&lt;/code&gt; attribute of &lt;code&gt;dialog&lt;/code&gt;, it will use the submit button of that form to close the dialog. If the form has only one button, it will use that one, or if it has multiple buttons, it will use the submit button. Again, this heavily suggests a specific use-case for the dialog element, where you’re collecting info from the user.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dialog&amp;gt;
  &amp;lt;form method=&quot;dialog&quot;&amp;gt;
    &amp;lt;button type=&quot;button&quot;&amp;gt;Close&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/dialog&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To open the dialog, some JavaScript is required. There are two methods that can be called, &lt;code&gt;.show()&lt;/code&gt; and &lt;code&gt;.showModal()&lt;/code&gt;. I wrongly assumed that these were the same, but they are not. &lt;code&gt;.show()&lt;/code&gt; will open the dialog in “non-modal” mode, whereas &lt;code&gt;.showModal()&lt;/code&gt; will open it in “modal” mode. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal&quot;&gt;Read more about showModal on MDN&lt;/a&gt;. And, to learn about the differences between modal and non-modal dialogs, &lt;a href=&quot;https://www.nngroup.com/articles/modal-nonmodal-dialog/&quot;&gt;Nielsen Norman has a great explainer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you need to customize the close functionality of the dialog, there is a &lt;code&gt;.close()&lt;/code&gt; method. This could be used for a “Cancel” button if you’ve got both a “Submit” and “Cancel” button.&lt;/p&gt;
&lt;p&gt;One thing that you get for free with the dialog element is that the escape key will close the dialog, no hooking up necessary. Absolutely delightful.&lt;/p&gt;
&lt;p&gt;Relatedly, a common pattern that people like to implement is the ability to close a dialog by clicking anywhere else on the page. This isn’t natively supported by the dialog element. There is no event listener for the backdrop element (as it’s a pseudo element and has the same limitations), so it would require an approach of &lt;a href=&quot;https://stackoverflow.com/questions/25864259/how-to-close-the-new-html-dialog-tag-by-clicking-on-its-backdrop&quot;&gt;listening for clicks on anything that isn’t the dialog itself&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Managing focus&lt;/h2&gt;
&lt;p&gt;A great perk of the dialog element is that it manages focus for you. When the dialog is opened, the first focusable element will receive focus, and then when the dialog is closed, focus will be returned to the element used to open the dialog. This is always tricky to manage, especially in cases where the context may change, the contents of the dialog may change, and all of that. Having it work out of a box is a great time saver.&lt;/p&gt;
&lt;h2&gt;Focus trap behavior&lt;/h2&gt;
&lt;p&gt;A second great perk of the dialog element is the browser-provided focus trap behavior. If you’re unfamiliar, this is what keeps your tab stops locked inside of an element when it’s active. In this case, when the dialog is open in its modal state, you can only tab to focusable elements in the dialog. The rest of the page is inaccessible.&lt;/p&gt;
&lt;p&gt;As previously mentioned, there is a modal and a non-modal version of the dialog. In the non-modal version, there is no focus trap, so this is another important difference between the two.&lt;/p&gt;
&lt;p&gt;Back to the modal version, one issue that seems a little strange to me is that the focus trap includes the address bar as a tab stop. This adds an extra step to get back around to the top of a dialog. However, a dialog is meant to represent a separate document (heading hierarchy should start over at h1 again), so I suppose that this sort of makes sense in that context.  Apparently this has been debated, as &lt;a href=&quot;https://nolanlawson.com/2022/06/14/dialogs-and-shadow-dom-can-we-make-it-accessible/&quot;&gt;Nolan Lawson details about halfway down in this article&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;It definitely feels like this element is ready for use, based on what I’ve read and noodled around with here. It’s not without its quirks, but it seems like those quirks are less than the quirks of the current manual approach, which is our benchmark here in the front-end world. &lt;a href=&quot;https://caniuse.com/?search=dialog&quot;&gt;Browser support is really good&lt;/a&gt;, but I’d really like to know more about how the element performs in different screen readers, and if screen reader users have any trouble with it before making it my default approach.&lt;/p&gt;
</content:encoded></item><item><title>Use button element to toggle parent menu items in WordPress</title><link>https://samhermes.com/posts/use-button-element-toggle-parent-menu-items-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/use-button-element-toggle-parent-menu-items-wordpress/</guid><pubDate>Sun, 25 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’re here for the code, skip to &lt;a href=&quot;#modifying-the-wordpress-navigation-markup&quot;&gt;Modifying the WordPress navigation markup&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The issues&lt;/h2&gt;
&lt;p&gt;Dropdowns are still ubiquitous across the web, and are still in various states of usability. One of the biggest possible issues is with the top level, or parent, menu item. Sometimes they are linked, and sometimes they act as a toggle. When linked, they can easily be missed, as the user is presented with the child items on hover, suggesting that they make a selection instead of starting with the parent.&lt;/p&gt;
&lt;p&gt;Additionally, if the top level menu item is a link, and its hover state acts as a way to reveal the child menu items, we run into several issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A user on a touchscreen device can end up being sent directly to the parent page, missing the child pages, and if those child pages aren’t linked to in the content of the parent page, they could be missed entirely. Someone may only get to them using search, at best.&lt;/li&gt;
&lt;li&gt;A keyboard user could tab to the parent menu item, and also have no way of toggling open the child menu items. Selecting the parent would go directly to the parent page, effectively replicating the touchscreen issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What to do about it?&lt;/h2&gt;
&lt;p&gt;Enter the button element! If we are going to have a dropdown, we need to have a toggle button available to the user. We have two approaches we could take:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The entire parent level item could be the toggle button. A user could press it, and the child pages are revealed. If we need to link to a “parent” page, this could be the first item in the dropdown, presented as something like “Overview.” This easily takes care of the problem. In some cases, this might free us from creating a landing page where it may not have even been necessary anyway. With this approach, we should place an arrow or chevron next to the text, to communicate how it works to the user, and help them differentiate between toggles and other menu items that are simply links without children.&lt;/li&gt;
&lt;li&gt;The parent level item could remain a link, and we could place the toggle button next to it. Again, similar to the previous approach, this could be presented as an arrow or chevron, but we would need to ensure that this is presented clearly enough that the user could understand that the parent is a link, and the button is a button. Visually, they’ll likely need some sort of separation, such as a border or background color.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Modifying the WordPress navigation markup&lt;/h2&gt;
&lt;p&gt;Out of the box, WordPress doesn’t have a way to use a button element in the navigation functions. For this post, I’m using &lt;code&gt;wp_nav_menu()&lt;/code&gt; to output a menu. This is a really easy function to use, but it has limited direct customization options for the markup. For that, we’ll need a filter.&lt;/p&gt;
&lt;p&gt;In the following function, it goes through each navigation item, checks to see if it is a parent, and then, if so, modifies the output to wrap the item in a button element. It isn’t done here, but we could narrow this to a specific menu if we needed or wanted to using &lt;code&gt;$args-&amp;gt;theme_location&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function projectname_parent_menu_item_buttons( $output, $item, $depth, $args ) {
  if ( in_array( &apos;menu-item-has-children&apos;, $item-&amp;gt;classes, true ) ) {
    $output = &apos;&amp;lt;button type=&quot;button&quot; class=&quot;menu-item-toggle&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;sub-menu-&apos; . $item-&amp;gt;ID . &apos;&quot;&amp;gt;&apos; . $item-&amp;gt;title . &apos;&amp;lt;/button&amp;gt;&apos;;
  }
  return $output;
}
add_filter( &apos;walker_nav_menu_start_el&apos;, &apos;projectname_parent_menu_item_buttons&apos;, 10, 4 );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this button to meet accessibility standards, we need to keep a couple of other items in mind. First, you’ll notice that there is an &lt;code&gt;aria-expanded&lt;/code&gt; attribute that’s been added to the button element. This tracks the current status of the dropdown menu, so that a screen reader user will know whether or not a dropdown is open when they land on this button. In PHP, we set the initial value to &lt;code&gt;false&lt;/code&gt;, but we’ll need to switch this to &lt;code&gt;true&lt;/code&gt; when the user opens the dropdown, and back to &lt;code&gt;false&lt;/code&gt; when they close it.&lt;/p&gt;
&lt;p&gt;Next, you’ll see &lt;code&gt;aria-controls&lt;/code&gt;. This needs to contain a unique ID, and tells a screen reader user which dropdown this button connects to. We apply the same ID to the dropdown element’s &lt;code&gt;id&lt;/code&gt; attribute, and ensure that this ID is not used anywhere else in the markup. This will likely require a walker, but could also be applied with JavaScript. Using the navigation item’s ID that WordPress gives us is a good starting place, and keeps us from needing to set all of this up ourselves, but we’ll want to use caution that this is truly unique.&lt;/p&gt;
</content:encoded></item><item><title>Getting to know theme.json</title><link>https://samhermes.com/posts/getting-to-know-theme-json/</link><guid isPermaLink="true">https://samhermes.com/posts/getting-to-know-theme-json/</guid><pubDate>Sat, 14 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When developing a custom WordPress theme for usage with the block editor, there can be an overwhelming amount of possibilities to account for. Countless settings, combinations, and layout conundrums can make it difficult to apply a consistent look and feel, whether it’s to match a brand, or just a casual blog. At its release, the block editor offered few ways of controlling these possibilities. Theme.json aims to address this, allowing theme authors to dramatically scale back the options and settings offered out of the box.&lt;/p&gt;
&lt;p&gt;There is thorough documentation on &lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/&quot;&gt;how to use theme.json on wordpress.org&lt;/a&gt;, so I won’t go into too much specific detail. I’d like to give context, look at what’s still missing, and give just enough info on how to get started.&lt;/p&gt;
&lt;h2&gt;What does theme.json do?&lt;/h2&gt;
&lt;p&gt;theme.json provides a way to disable controls in the block editor, both in the block toolbar (immediately above a block when it’s selected) and in the inspector controls (right sidebar, gear icon). So, think of font sizes, color selectors, button radius. In addition, it provides a mechanism for tweaking the default styles used by the block editor in the admin and on the front end. This could be global typography styles, or something as simple as the space between columns in the column block.&lt;/p&gt;
&lt;p&gt;On a more “experimental” or “beta” note, theme.json provides controls for &lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/block-theme-overview/&quot;&gt;block themes&lt;/a&gt;, but that’s a topic for another day. It appears that the styles control provided by theme.json is also geared heavily towards block themes as well.&lt;/p&gt;
&lt;h3&gt;Opt-in controls&lt;/h3&gt;
&lt;p&gt;By and large, theme.json exists to disable controls, but there is a small subset of “opt-in” controls, which can be enabled via theme.json, either individually or wholesale using &lt;code&gt;appearanceTools&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;. Documentation on what these are is &lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/#opt-in-into-ui-controls&quot;&gt;available on wordpress.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most interesting of them is the &lt;code&gt;spacing&lt;/code&gt; control, which seems to be quite limited at this time, but holds potential. It would be nice if we could move away from the core spacer block.&lt;/p&gt;
&lt;p&gt;Included in the list is also &lt;code&gt;border&lt;/code&gt; controls, which seems to be in a strange state, as there are border controls on a few different blocks by default. I’m not sure what opting in to border controls adds. I did find that I had to disable border controls on a block-by-block basis, attempting to disable globally didn’t have any effect. See the example at the bottom of this post.&lt;/p&gt;
&lt;h3&gt;Looking down the road&lt;/h3&gt;
&lt;p&gt;For better or worse, applying changes to theme.json does not update any block retroactively. So, disabling the font size control will not revert the font size to the default on any existing block that has a custom font size. Depending on your circumstances, this could be good. It does suggest to me that it might be best to start a project with almost everything disabled, and then enable features as needed to avoid content from getting away from you, especially in those cases where many people could be editing the content of the site.&lt;/p&gt;
&lt;p&gt;On the flip side, removing a color from a color palette does, in fact, remove it from any block currently using it. There is the possibility of continuing to support a color, however, by defining styles to match the appropriate class names in your theme stylesheet.&lt;/p&gt;
&lt;h2&gt;What does this replace?&lt;/h2&gt;
&lt;p&gt;For those who are already familiar with theme development in a block editor world, theme.json seeks to replace the accumulating list of formatting-related &lt;code&gt;add_theme_support()&lt;/code&gt; options that have cropped up since the block editor’s inception. As these were getting to be unwieldy, theme.json seeks to provide a more extensible approach. The theme.json documentation provides a &lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/#backward-compatibility-with-add_theme_support&quot;&gt;list of equivalents&lt;/a&gt;. In short, theme.json takes precedence, so any &lt;code&gt;add_theme_support()&lt;/code&gt; calls related to the block editor that you’re making in functions.php should be migrated over.&lt;/p&gt;
&lt;p&gt;Fortunately, theme.json expands the possibilities compared to what is available via &lt;code&gt;add_theme_support()&lt;/code&gt;, so, while it’s a bit of work to get spun up, this is a better long term approach.&lt;/p&gt;
&lt;p&gt;For those of us who were scrambling to tamp down the block editor soon after it was merged into core, this also hopefully replaces any of the hacky CSS that was required to hide any control that did not have a matching &lt;code&gt;add_theme_support()&lt;/code&gt; for it. Which, at the time, was most controls.&lt;/p&gt;
&lt;h3&gt;Custom color palette&lt;/h3&gt;
&lt;p&gt;Part of the conversion from &lt;code&gt;add_theme_support()&lt;/code&gt; to theme.json, is, of course, color palettes. I’m certainly in favor of this, as it is now as simple as defining the color names and values in theme.json, and letting WordPress do the rest. Previously, as you may know, you needed to define all of the colors using &lt;code&gt;add_theme_support()&lt;/code&gt;, and then additionally define them in your own stylesheet (with all the appropriate class names) to get them to actually work on the front end.&lt;/p&gt;
&lt;p&gt;In general, it’s nice to see WordPress moving more into custom properties, as it makes modifications much easier from a theme development standpoint. Custom properties ftw!&lt;/p&gt;
&lt;h3&gt;Block editor width&lt;/h3&gt;
&lt;p&gt;Previously, to adjust the max-width of the block editor, it would require an &lt;code&gt;editor-style.css&lt;/code&gt; stylesheet to be enqueued, and a style selector of &lt;code&gt;.wp-block { max-width: 750px; }&lt;/code&gt;, as an example. Now, this can be handled through theme.json.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;layout&quot;: {
    &quot;contentSize&quot;: &quot;750px&quot;,
    &quot;wideSize&quot;: &quot;1200px&quot;
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This still does not address the issue of differing content widths on different post types. Wide pages and narrow posts, anyone? Is that so rare? Please tell me I’m missing something?&lt;/p&gt;
&lt;h2&gt;What doesn’t theme.json do?&lt;/h2&gt;
&lt;p&gt;You could read this heading quite optimistically, but I’m afraid that that isn’t the case. To disable any of the following, it appears to still &lt;a href=&quot;https://samhermes.com/posts/disabling-blocks-block-styles-gutenberg/&quot;&gt;require a little JS in the editor&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Disable core blocks completely with &lt;code&gt;wp.blocks.unregisterBlockType()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Disable style options associated with core blocks with &lt;code&gt;wp.blocks.unregisterBlockStyle()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Disable inline formatting options with &lt;code&gt;wp.richText.unregisterFormatType()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How to get started&lt;/h2&gt;
&lt;p&gt;It should be noted that theme.json is on version 2 already, so caution should be applied when using examples floating around. They could be out of date and not work as expected. The best documentation remains on &lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/&quot;&gt;wordpress.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To start, create a file called &lt;code&gt;theme.json&lt;/code&gt; in the root of your theme. WordPress will automatically pick this file up, so its very existence is enough.&lt;/p&gt;
&lt;p&gt;The contents of the theme have to be in JSON format. There are a lot of possibilities, so a schema was created to assist. In Visual Studio Code, it will use the schema to suggest supported options, and fill the default value when a suggestion is selected. It will also let you know of any misspellings.&lt;/p&gt;
&lt;p&gt;The very basic structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;$schema&quot;: &quot;https://schemas.wp.org/trunk/theme.json&quot;,
  &quot;version&quot;: 2,
  &quot;settings&quot;: {},
  &quot;styles&quot;: {},
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most of the action takes place under &lt;code&gt;settings&lt;/code&gt;. There, it’s broken down into global settings and block-level settings. You can define a global setting, and then override it on specific blocks. For example, you could disable custom font sizes across the board, and then re-enable them on just the heading block. You can see &lt;a href=&quot;https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/#settings-examples&quot;&gt;examples of this on wordpress.org&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Sample theme.json starter&lt;/h2&gt;
&lt;p&gt;This is what I’m currently using to start my projects with. It disables some of the more freeform controls, while leaving some of the basics in tact. It disables the default color palette, with the assumption that this will be set on a project-by-project basis.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;$schema&quot;: &quot;https://schemas.wp.org/trunk/theme.json&quot;,
  &quot;version&quot;: 2,
  &quot;settings&quot;: {
    &quot;color&quot;: {
      &quot;custom&quot;: false,
      &quot;customDuotone&quot;: false,
      &quot;customGradient&quot;: false,
      &quot;defaultGradients&quot;: false,
      &quot;defaultPalette&quot;: true
    },
    &quot;layout&quot;: {
      &quot;contentSize&quot;: &quot;750px&quot;,
      &quot;wideSize&quot;: &quot;1200px&quot;
    },
    &quot;typography&quot;: {
      &quot;customFontSize&quot;: true,
      &quot;dropCap&quot;: false,
      &quot;fontStyle&quot;: false,
      &quot;fontWeight&quot;: false,
      &quot;letterSpacing&quot;: false,
      &quot;textDecoration&quot;: false,
      &quot;textTransform&quot;: false
    },
    &quot;blocks&quot;: {
      &quot;core/button&quot;: {
        &quot;border&quot;: {
          &quot;radius&quot;: false
        }
      },
      &quot;core/pullquote&quot;: {
        &quot;border&quot;: {
          &quot;color&quot;: false,
          &quot;radius&quot;: false,
          &quot;style&quot;: false,
          &quot;width&quot;: false
        }
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Detect when an image has loaded with JavaScript</title><link>https://samhermes.com/posts/detect-when-image-has-loaded-javascript/</link><guid isPermaLink="true">https://samhermes.com/posts/detect-when-image-has-loaded-javascript/</guid><pubDate>Tue, 11 Jan 2022 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;When you’re wanting to make something happen after an image has completely loaded, you need an event to attach your script to. This can be a little tricky to get right, but with a combination of event listeners and the image &lt;code&gt;complete&lt;/code&gt; attribute, it’s possible.&lt;/p&gt;
&lt;p&gt;Before I get carried away with this custom approach, I want to call out that a package exists to handle this called &lt;a href=&quot;https://imagesloaded.desandro.com&quot;&gt;imagesLoaded&lt;/a&gt;. I haven’t used this myself, but it would probably be more appropriate for a larger project where images are a key feature.&lt;/p&gt;
&lt;h2&gt;The image &lt;code&gt;complete&lt;/code&gt; attribute&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;complete&lt;/code&gt; attribute (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete&quot;&gt;MDN&lt;/a&gt;) is the key to this approach. Essentially, we need to look to this attribute to get a status of whether or not an image has loaded.&lt;/p&gt;
&lt;p&gt;Critically, we need to define what “complete” really means here. It can be true if an image is ready to display, but it can also be true if the image failed. This complicates matters, as we’ll need to check the &lt;code&gt;complete&lt;/code&gt; attribute, and also verify that the image load was a success.&lt;/p&gt;
&lt;h2&gt;The &lt;code&gt;load&lt;/code&gt; event listener&lt;/h2&gt;
&lt;p&gt;The other half of this approach is the event listener. This is similar to other common event listeners, where it fires when something changes. Instead of a keystroke, we listen for the image to communicate that it has loaded.&lt;/p&gt;
&lt;p&gt;The nuance with this event listener is that we want to use the &lt;code&gt;complete&lt;/code&gt; attribute, and only apply the event listener if the image is not complete. If it’s already loaded, whether it just downloaded before our listener was attached, or is cached in the browser, we don’t need to listen for the &lt;code&gt;load&lt;/code&gt; event, as it won’t happen.&lt;/p&gt;
&lt;p&gt;I’ve also included an event listener for an &lt;code&gt;error&lt;/code&gt; event, in case the image fails to load for whatever reason. This could be used to show an error message, or offer the user an alternative.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const image = document.querySelector(&apos;.container img&apos;);
if ( !image.complete) {
  image.addEventListener(&apos;load&apos;, handleImageLoad);
  image.addEventListener(&apos;error&apos;, handleImageLoad);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The listener function&lt;/h2&gt;
&lt;p&gt;Now that we have a way to check the image status, and we’re listening for the &lt;code&gt;load&lt;/code&gt; event, we need a function to actually make something happen. In this example, the function removes an active class from the container. We could use this in our CSS to show/hide the loading animation or image.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const handleImageLoad = () =&amp;gt; {
  container.classList.remove(&apos;is-loading&apos;);
  image.removeEventListener(&apos;load&apos;, handleImageLoad)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, you may have noticed, this function also removes the event listener from the image. This is good cleanup to do so that the browser isn’t waiting for anything else to happen with the image.&lt;/p&gt;
</content:encoded></item><item><title>Returning to Eleventy</title><link>https://samhermes.com/posts/returning-to-eleventy/</link><guid isPermaLink="true">https://samhermes.com/posts/returning-to-eleventy/</guid><pubDate>Mon, 22 Nov 2021 13:02:00 GMT</pubDate><content:encoded>&lt;p&gt;Well, well, well, dear reader. I&apos;m back. After leaving &lt;a href=&quot;https://samhermes.com/posts/my-attempt-to-convert-from-jekyll-to-eleventy/&quot;&gt;my last post&lt;/a&gt; on &quot;It&apos;s exhausting,&quot; I&apos;ve resumed digging into Eleventy. In fact, if you&apos;re reading this, it was generated by Eleventy! Here&apos;s what I did between my last post and now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gave up on tags/categories. That&apos;ll fix it!&lt;/li&gt;
&lt;li&gt;Gave up on Siteleaf. I&apos;ll just add posts manually again.&lt;/li&gt;
&lt;li&gt;Discovered Cloudflare Pages. It allows for static sites to be easily deployed from a GitHub repository, and automatically re-deploys on each new commit. You can choose the branch, and set the build command. Also, as my DNS was already being handled by Cloudflare, switching it from GitHub Pages to Cloudflare Pages was literally so easy. No downtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&apos;s it. That&apos;s all it took. Now, granted, I still had to figure out all that other stuff in my last post. It was kind of a lot. Also, I discovered a few Eleventy plugins that handled some of my outstanding concerns quite nicely.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;@11ty/eleventy-plugin-syntaxhighlight&lt;/code&gt;
&lt;a href=&quot;https://www.11ty.dev/docs/plugins/syntaxhighlight/&quot;&gt;https://www.11ty.dev/docs/plugins/syntaxhighlight/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Previously, I was using PrismJS on the front end to handle code blocks. I&apos;d add a &lt;code&gt;custom_js&lt;/code&gt; declaration to the front matter of each post I wanted to add it to, as to only load the script on  posts with code. This was a little frustrating, as I often forgot to add it on first publish, and then I&apos;d have to go back and add it.&lt;/p&gt;
&lt;p&gt;With the Eleventy plugin, this script runs as part of the build process, and is no longer needed on the front end. This is absolutely fantastic. Okay fine fine fine, it&apos;s nice when &lt;em&gt;some&lt;/em&gt; things are all JavaScript.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;@11ty/eleventy-plugin-rss&lt;/code&gt;
&lt;a href=&quot;https://www.11ty.dev/docs/plugins/rss/&quot;&gt;https://www.11ty.dev/docs/plugins/rss/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;RSS works fairly similarly to how it worked in Jekyll, except that Jekyll had it built in by default. I&apos;m not sure that I even really need RSS on my site, but it&apos;s there. Also, in the old site, I had a feed.json, which was just a JSON version of the RSS feed. I did a little searching around, and it looks like everyone was very excited about JSON feeds in Spring/Summer of 2017 and then never said anything about it again. So, I let that one go.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What did we learn? Sometimes, you have to step away for a whole month, and then when you come back, the problems aren&apos;t as big, and the finish line isn&apos;t that far away. A little caffeine didn&apos;t hurt either.&lt;/p&gt;
</content:encoded></item><item><title>Fade in and out element with CSS transition</title><link>https://samhermes.com/posts/fade-in-and-out-element-with-css-transition/</link><guid isPermaLink="true">https://samhermes.com/posts/fade-in-and-out-element-with-css-transition/</guid><pubDate>Fri, 05 Nov 2021 11:15:00 GMT</pubDate><content:encoded>&lt;p&gt;Here we have an element that is using &lt;code&gt;position: absolute&lt;/code&gt;, and is not visible when the page loads or by default. In this case, we can rely on &lt;code&gt;visibility&lt;/code&gt; to control whether or not the element is visible. As the element is using &lt;code&gt;position: absolute&lt;/code&gt;, it doesn&apos;t matter if it continues to take up space when its hidden, one of the gotchas of using &lt;code&gt;visibility: hidden&lt;/code&gt;. Here, we transition opacity to give the fade in/out effect.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.class-name {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s cubic-bezier(0.2, 1, 0.3, 1), visibility 0s 0.5s;

  &amp;amp;.is-active { /* This could be :hover on a parent element additionally or instead */
    opacity: 1;
    visibility: visible;
    transition: opacity 0.5s cubic-bezier(0.2, 1, 0.3, 1);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, what’s the trick here? It’s the delay on visibility on fade out. For the transition back to the default state only, we add a transition to visibility with a duration of 0s and a delay of 0.5s, matching the duration of the opacity transition. This allows us to see the opacity being transitioned before the visibility is set to hidden. There is no transition that could be applied to visibility, so we’re really just taking advantage of the ability to delay it.&lt;/p&gt;
</content:encoded></item><item><title>My attempt to convert from Jekyll to Eleventy</title><link>https://samhermes.com/posts/my-attempt-to-convert-from-jekyll-to-eleventy/</link><guid isPermaLink="true">https://samhermes.com/posts/my-attempt-to-convert-from-jekyll-to-eleventy/</guid><pubDate>Fri, 15 Oct 2021 11:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Update 11/22/21: I have published a &lt;a href=&quot;https://samhermes.com/posts/returning-to-eleventy/&quot;&gt;follow-up post&lt;/a&gt;, where I finally bring this all together.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Usually when I write something, it’s because I’ve figured something out, or done something for the first time. But, that’s like 1% of the things that happen. In this case, I thought I’d try out Eleventy, and see about converting my site from Jekyll. After getting stuck on all kinds of weird things, I gave up. I questioned my career choice. I stared longingly out of a window. I ate bread. So, this isn’t really a conversion guide, but more of a report? There are things here that are likely obvious to others, or there are things here that probably should be better documented.&lt;/p&gt;
&lt;h2&gt;Installation &amp;amp; Layouts&lt;/h2&gt;
&lt;p&gt;This part was super easy! I’m familiar with node, and all that entails, so installing Eleventy and configuring it was very straightforward. It felt like a great fit. With that done, I began running into issues. The first was surrounding the templates. Eleventy expects them to be in a folder called &lt;code&gt;_includes&lt;/code&gt;, but Jekyll wants them to be in a folder called &lt;code&gt;_layouts&lt;/code&gt;. Thanks to &lt;a href=&quot;https://alexpearce.me/2020/06/jekyll-to-eleventy/&quot;&gt;this article by Alex Pearce&lt;/a&gt;, I found I could just modify this with a setting in &lt;code&gt;.eleventy.js&lt;/code&gt; (a file that must be created).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = {
  dir: {
    layouts: &quot;_layouts&quot;
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that the layouts were looking in the right place, I stumbled around trying to get them to be applied appropriately until I found out (&lt;a href=&quot;https://kittygiraudel.com/2020/11/30/from-jekyll-to-11ty/&quot;&gt;from this article by Kitty Giraudel&lt;/a&gt;) that each “collection” in Eleventy uses a configuration file in their directory to apply this across the board. So, for my “posts” collection, I added a file called &lt;code&gt;_posts.json&lt;/code&gt;, and added the following.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;layout&quot;: &quot;post&quot;,
  &quot;permalink&quot;: &quot;/posts/{{ page.fileSlug }}/&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only problem was, the posts were nowhere to be found. My homepage had an empty spot where they were supposed to be.&lt;/p&gt;
&lt;p&gt;The next thing that I tried was explictly defining my collections in the configuration file. There, I added each of my collections, one for posts, categories, and projects. For example, here’s the posts definition:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.addCollection(&apos;posts&apos;, collection =&amp;gt;
  collection.getFilteredByGlob(&apos;_posts/*.md&apos;)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, projects and categories were showing up, but still no posts. The answer is actually in the code snippet above.&lt;/p&gt;
&lt;p&gt;It was the file extension. Through my copy-pasting, I had set it up to look for files with the extension of &lt;code&gt;.md&lt;/code&gt;. All of my posts were using the &lt;code&gt;.markdown&lt;/code&gt; extension. Jekyll doesn&apos;t really mind which one you use, so this was a silly thing I didn’t think of right away.&lt;/p&gt;
&lt;p&gt;I decided to update the extension. In Finder, if you select a bunch of items, and select “Rename…,” the default is to replace a string, so you can just type in the old extension, and then the new extension, and it’s that easy. Once I had completed this, the posts all began being processed by Eleventy.&lt;/p&gt;
&lt;p&gt;A similar issue I faced with some of my pages was markup being output instead of actually rendering HTML. Previously, I had all of my pages using the &lt;code&gt;.md&lt;/code&gt; extension, but converting them all to &lt;code&gt;.liquid&lt;/code&gt; fixed this issue. This conversion made sense, as many of them are only liquid syntax, Jekyll was just sort of figuring it all out before.&lt;/p&gt;
&lt;p&gt;Last, there was a small issue with the post date. Any place I was displaying the date, there was “%-d” where the day should have been. The complete liquid syntax I was using was this: &lt;code&gt;{{ post.date | date: &quot;%B %-d, %Y&quot; }}&lt;/code&gt; Apparently this is a Ruby thing, and the proper liquid format is &lt;code&gt;%e&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Sass&lt;/h2&gt;
&lt;p&gt;Eleventy does not doing anything with Sass by default. This was a surprise to me, only because I’ve been so used to Jekyll having it built in by default. It makes total sense that Eleventy would leave this open-ended. Still, it required a little configuration to get it working as it was before.&lt;/p&gt;
&lt;p&gt;I needed to install the &lt;code&gt;sass&lt;/code&gt; package first.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install sass --save-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, I needed to integrate it with the build. Before, I was just using the default &lt;code&gt;eleventy —serve&lt;/code&gt; command, but with the additional step of building styles, I set up custom commands in &lt;code&gt;package.json&lt;/code&gt;. I learned how to do all of this from &lt;a href=&quot;https://jkc.codes/blog/using-sass-with-eleventy/&quot;&gt;this article by John Kemp-Cruz&lt;/a&gt;. Honestly, the most fun part of not knowing what you&apos;re doing is visiting all of these personal sites.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;watch:eleventy&quot;: &quot;eleventy --serve&quot;,
&quot;watch:sass&quot;: &quot;sass _sass:_site/css --watch&quot;,
&quot;start&quot;: &quot;npm run watch:eleventy &amp;amp; npm run watch:sass&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last little bit was to connect updates to sass files to BrowserSync, so that it would reload the browser when any of the sass files changed. This works out of the box for everything else in Eleventy, and it’s easy to add files to the watch list. In &lt;code&gt;.eleventy.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.setBrowserSyncConfig({
  files: &apos;./_site/css/**/*.css&apos;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Tags&lt;/h2&gt;
&lt;p&gt;This is really where everything came crashing down. Previously, through the front matter on my posts, I’d add in a list of strings for the post categories. For example, here’s the front matter for this post:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: My attempt to convert from Jekyll to Eleventy
date: 2021-10-15 11:30:00 Z
categories:
- JavaScript
- Jekyll

---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Admittedly, the way that I’m handling categories in Jekyll is not super great. I created collection and a markdown file for each category that I wanted to make an archive for.&lt;/p&gt;
&lt;p&gt;Eleventy seems to be able to handle this in a much easier way, but I still haven’t been able to get it to work. In the front matter above, I updated “categories” to “tags,” to take advantage of the tagging system that is built in. I then created a template in the root of my project called &lt;code&gt;tags.njk&lt;/code&gt; and used the same configuration as the &lt;a href=&quot;https://github.com/11ty/eleventy-base-blog/blob/master/tags.njk&quot;&gt;template file in the Eleventy base blog repo&lt;/a&gt;. I assumed that this would just work, but I couldn&apos;t get any posts to show up. The tag pages would be created, but nothing would be on them.&lt;/p&gt;
&lt;p&gt;At this point, it just felt like I was trying to do something that wasn’t meant to be. Looking at the Eleventy base blog repo, I considered attempting to start something “fresh,” and that would probably fix the issue, but would I know why?&lt;/p&gt;
&lt;h2&gt;Deployment &amp;amp; Updates&lt;/h2&gt;
&lt;p&gt;Previously, with Jekyll, I could just push my changes to GitHub, and then it would build my site and deploy it to GitHub pages automatically. This was a super seamless process, only occasionally tripped up by the Jekyll version being different between my local and GitHub.&lt;/p&gt;
&lt;p&gt;For Eleventy, I knew that it wasn’t going to be quite as easy, but I imagined that it had been done already. I searched around for some information. I didn’t find anything. I looked at the GitHub Pages information, but it mostly focuses on using Jekyll. I wondered if I could just change the publishing source to the &lt;code&gt;_site&lt;/code&gt; folder, but couldn&apos;t find anything in the GitHub repo settings to do so. This is an overlap with Jekyll and Eleventy, so I wondered if it would just know to publish from that folder anyway?&lt;/p&gt;
&lt;p&gt;Additionally, I have been using Siteleaf to make updates to my site. It’s just much quicker to launch a GUI, paste in the contents of a post, and then save. However, Siteleaf is also designed to work with Jekyll and doesn’t have a way to use anything else. It appears it &lt;a href=&quot;https://github.com/siteleaf/community/discussions/14&quot;&gt;might happen in the future&lt;/a&gt;, but that’s likely a ways off.&lt;/p&gt;
&lt;p&gt;With Siteleaf a dead end, I went on to explore Netlify, which I&apos;ve experimented with in the past. They have a CMS product that allows you to make updates to your site, so I wondered about using it instead of Siteleaf. There, I found a template that would handle all of this, the &lt;a href=&quot;https://templates.netlify.com/template/eleventy-netlify-boilerplate/&quot;&gt;Eleventy + Netlify CMS Boilerplate&lt;/a&gt;. They make it super easy to just press a button, and then press several other buttons. I left off here, though, as using this boilerplate would essentially require me to rebuild my site. Not a huge process, but it brought be back to where I left off with tags.&lt;/p&gt;
&lt;h2&gt;And that’s where I am today.&lt;/h2&gt;
&lt;p&gt;I might be just on the precipice of bringing this all together, but I’m tired. I’m so, so tired. This is what everything in web development is like. I liked Jekyll in the beginning because it used markdown, and that felt like a good, fairly future-proof decision. It mostly is. I like using standard tooling, which Eleventy feels like. It also includes the joyously overfilled &lt;code&gt;node_modules&lt;/code&gt; folder. I can&apos;t believe this is still how things work. Still, I know JavaScript, so it felt good to begin with. After that, as you can see above, it was just a lot of struggle. No individual thing is that big of a deal, but cumulatively, it&apos;s so much work.&lt;/p&gt;
&lt;p&gt;Eleventy is great for a fresh project, and I don’t want to fault Eleventy specifically here. It just happens to be the latest thing I attempted to use. I generally don’t enjoy the wrestling phase of anything new, it’s really not what keeps me interested. I usually get down on myself and question everything. I like when things are working, running smoothly, and I understand them. When this wrestling phase is happening all of the time, I just feel so unsettled. That’s web development though. It’s exhausting.&lt;/p&gt;
</content:encoded></item><item><title>The journey to Alexander</title><link>https://samhermes.com/posts/the-journey-to-alexander/</link><guid isPermaLink="true">https://samhermes.com/posts/the-journey-to-alexander/</guid><pubDate>Wed, 29 Sep 2021 00:32:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve long been interested in design systems, pattern libraries, front end frameworks, and the like. Naturally, for no good reason, I’ve wanted to create one of my own, putting my spin on it and filling it with all of my opinions. Despite a long list of reasons not to, I decided to wade into this project earlier this year.&lt;/p&gt;
&lt;p&gt;I began listing out all of the components I wanted to create, from buttons to cards to accordions, and then began researching the best way to make a foundation to support it all. I planned to make a color palette, custom styles for all of the basic elements, and then bundle it up in a way to make it easy to insert into a project. In essence, I did what everyone else has done. The further along I got, the emptier it felt. I lost track of why I was doing it.&lt;/p&gt;
&lt;p&gt;For a little while, I was stuck there. I was teetering on going full steam ahead or totally scrapping it. Either way felt reasonable. Finally, after spending an afternoon on a remote mountain top, it hit me. The reason I was making this was not to make a design system, but to take what I’ve learned about front end so far and to put that into a product. Lightbulb.&lt;/p&gt;
&lt;p&gt;With this, I redirected my energy into documenting just the things I felt I had something to say about. Anything that had been answered in a better way somewhere else, I removed. Anything that felt like a specific design implementation, I removed. Partially relieved at having less to do, and partially energized by a new focus, I found myself at a version 1. And that’s about where I am today. I plan to grow and adapt it as I go, treating it primarily as a reference point for myself.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/samhermes/alexander&quot;&gt;Alexander&lt;/a&gt; looks like a front end framework. And it is, sort of. It’s also a place for me to ask questions and go down rabbit holes in a place that’s outside of any project I’m working on. Why are we still using browser resets? Can we separate global and component level styles? Can accessibility be separate from branding? How modular can I get? Why does every design system have to solve the same base level problem? What browser defaults are best left alone?&lt;/p&gt;
&lt;p&gt;I&apos;ve used Underscores for my WordPress work for so long. It includes Normalize as its starting point, and this has always seemed appropriate to me. I&apos;m beginning to question this approach of just wholesale including a stylesheet like that though. How many sites have I put out there with these extra styles, when they were never needed for the site? That&apos;s an obvious area for improvement.&lt;/p&gt;
&lt;p&gt;A lot of the styles that are included in Normalize or a similar reset/starter have to do with form elements. At least in the context of WordPress, I rely on a form plugin to handle forms, and those plugins come with their own stylesheet. Ninja Forms includes form reset styles. So, I&apos;ve been double reset-ing. Not great. The most I’ll do outside of Ninja Forms is add a search field, which I usually style enough to handle any inconsistencies anyway.&lt;/p&gt;
&lt;p&gt;On a broader scope, I’ve always been bewildered by using Bootstrap wholesale for anything. To include a bunch of assets in a project that may or may not use them seems super wasteful. For a larger system where you don&apos;t know what elements will be used, sure, it makes perfect sense. For a small site? No. I do, however, look at it for reference regularly, and I think that this kind of usage makes a lot of sense, as it gives you a really great starting point. They’ve already thought through performance, browser consistency, accessibility, long term maintenance, not to mention common interaction patterns.&lt;/p&gt;
&lt;p&gt;This brings me a second area of concern, probably best highlighted by Bootstrap. What’s the best way to adapt reusable components for a specific design? Sure, Bootstrap offers a way to control the presentation of components, but things can just get messy really quickly. Changing the markup at all would essentially fork the component. I wanted to take a stab at this, and worked on Alexander with two distinct layers. These two layers are visible throughout the documentation by using the toggle button on each demo.&lt;/p&gt;
&lt;p&gt;The difficulty of this exercise was deciding exactly where to draw the line. Some styles are needed in order for each component to function at a base level, but finding where those cross over into a design implementation took some second-guessing. Additionally, the animations and interactions that I implemented were specific enough not to work in every situation. Those are much less flexible, and difficult to make more flexible. The limits of JavaScript strike again. Were some of these interactions built into the browser, these components could be far more robust, but we’re working with what we’ve got.&lt;/p&gt;
&lt;p&gt;In the long run, to make the call on whether or not this project was successful, I’ll need to use it on a real project. That will take time, and will result in changes, but I think it’s in a really good place now, and I’m excited to have those opportunities. Like I said, I hope to continue growing and changing Alexander as I learn more.&lt;/p&gt;
</content:encoded></item><item><title>How to make accessible accordions</title><link>https://samhermes.com/posts/how-to-make-accessible-accordions/</link><guid isPermaLink="true">https://samhermes.com/posts/how-to-make-accessible-accordions/</guid><pubDate>Sun, 22 Aug 2021 20:29:00 GMT</pubDate><content:encoded>&lt;p&gt;The time has finally come. I&apos;m going to try and make accessible accordions. This, I know, has been solved by literally so many people. They are in every design system. They litter CodePen. It’s a bit of a goldilocks problem, though. Some of them are too simple, some of them are too complicated. Some of them are, rightly so, very specific. I&apos;ve made quite a few of them myself, and each time I go to make them, I start somewhere different.&lt;/p&gt;
&lt;p&gt;The biggest concern with accordions is making them accessible, which is a baseline requirement. Sure, they should look good and preferrably have a nice animation, but they need to be accessible first. At their very core, they are simply a pairing of a heading and some content. Take away the accordion, and the hierarchy should still make sense.&lt;/p&gt;
&lt;h2&gt;The markup&lt;/h2&gt;
&lt;p&gt;Whether it&apos;s through a CMS or hand-coded, accordions do require some special markup to start with. With Gutenberg in WordPress, or whatever building solution, it can be easy to make this super simple to set up for the first time, and then use anywhere. In fact, the more that that can happen, the better, as standards evolve, and making updates as easy as possible is a win for everyone.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;accordion&quot;&amp;gt;
    &amp;lt;div class=&quot;accordion-heading&quot;&amp;gt;
        &amp;lt;h3&amp;gt;Accordion heading&amp;lt;/h3&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;accordion-content&quot;&amp;gt;
        &amp;lt;p&amp;gt;Accordion content&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, before we get carried away, we&apos;ve already introduced a heading into this accordion, which is setting off accessibility alarms. Whether it&apos;s in HTML, or in editors like Gutenberg, it&apos;s important that accordion heading levels can be adjusted. We should never lock a heading level, or assume that we know what it will always be. It must be contextual. We&apos;ll add styles so that it always looks the same while in an accordion, no matter what level.&lt;/p&gt;
&lt;h2&gt;Starting the script&lt;/h2&gt;
&lt;p&gt;As we don’t want to limit ourselves to a single accordion per page, we’ll want to keep multiple accordions in mind as we start the script. To keep this as simple as possible, I’ve used &lt;code&gt;querySelectorAll&lt;/code&gt;. I&apos;m also just using &lt;code&gt;.accordion&lt;/code&gt;, which could run into conflicts if being used alongside other plugins or scripts, so it might be worth prefixing this for your specific project.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const accordions = document.querySelectorAll(&apos;.accordion&apos;);

accordions.forEach((accordion, index) =&amp;gt; {

});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will give us an array of all of the accordions on the page, and we can loop through each of them with &lt;code&gt;forEach&lt;/code&gt;, applying the same modifications to each.&lt;/p&gt;
&lt;p&gt;Next, we want to grab the heading and content elements, to get those ready for modifications that we’ll need to make. We can take advantage of &lt;code&gt;accordion&lt;/code&gt; to narrow our scope for &lt;code&gt;querySelector&lt;/code&gt;, so it will only get the heading and content of the current accordion. I like to store this in an object to make it easier to reference later and understand.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const elements = {
    heading: accordion.querySelector(&apos;.accordion-heading&apos;),
    content: accordion.querySelector(&apos;.accordion-content&apos;),
    headingChildren: accordion.querySelector(&apos;.accordion-heading &amp;gt; *&apos;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Wrapping the heading in a button&lt;/h2&gt;
&lt;p&gt;As we’ll only turn this markup into an accordion if JavaScript is enabled, it makes sense to modify the markup through JavaScript as well. Additionally, this prevents the user from needing to add them, so it enforces consistency.&lt;/p&gt;
&lt;p&gt;First, we need to wrap the accordion heading in a button element. The easiest way that I’ve found to do this is to use &lt;code&gt;createElement&lt;/code&gt; and then set attributes as needed. This is just a toggle button, so it needs a &lt;code&gt;type&lt;/code&gt; of &lt;code&gt;button&lt;/code&gt;. On the CSS side of this, you&apos;ll likely want to remove almost all of the default button styles, whether that&apos;s just the browser defaults, or global button styles inside of your project. It needs to act like a button, not necessarily look like it. As always, either leave the browser default outline styles in place, or be sure to add your own custom focus styles. The user should know where their focus state is at all times.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const button = document.createElement(&apos;button&apos;)
button.setAttribute(&apos;type&apos;, &apos;button&apos;)

button.appendChild(elements.headingChildren)
elements.heading.appendChild(button)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Adding accessibility attributes&lt;/h2&gt;
&lt;p&gt;Now that we have a button, it’s time to start setting the proper attributes. We need to tie the heading/button to the content, so we add &lt;code&gt;aria-controls&lt;/code&gt; first, using the &lt;code&gt;index&lt;/code&gt; provided by &lt;code&gt;forEach&lt;/code&gt;. Next, we set &lt;code&gt;aria-expanded&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; to signify that the accordion is currently closed, but if it were to be open when the page loads, then the value should be set to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;button.setAttribute(&apos;aria-controls&apos;, &apos;accordion-&apos; + index)
button.setAttribute(&apos;aria-expanded&apos;, &apos;false&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, for the heading content, we need to add the corresponding &lt;code&gt;aria-controlledby&lt;/code&gt; that matches what we&apos;ve set on the button.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;elements.content.setAttribute(&apos;aria-controlledby&apos;, &apos;accordion-&apos; + index)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Adding an event listener&lt;/h2&gt;
&lt;p&gt;Now that we have all of the attributes added, we need to appropriately toggle them when the user clicks on the button. Additionally, I like to add a class to the containing element for styling purposes.&lt;/p&gt;
&lt;p&gt;This relies on the &lt;code&gt;aria-expanded&lt;/code&gt; attribute of the button to determine what to do. This entertwines the open and close actions with accessibility, ensuring that we aren&apos;t getting those out of sync at any time.&lt;/p&gt;
&lt;p&gt;Here, we call an open and close function to handle both updating attributes as necessary and handling animation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;button.addEventListener(&apos;click&apos;, () =&amp;gt; {
    const expanded = button.getAttribute(&apos;aria-expanded&apos;)
    expanded === &apos;true&apos; ? button.setAttribute(&apos;aria-expanded&apos;, &apos;false&apos;) : button.setAttribute(&apos;aria-expanded&apos;, &apos;true&apos;)

    if (expanded === &apos;true&apos;) {
        closeAccordion(accordion, elements)
    } else {
        openAccordion(accordion, elements)
    }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Opening &amp;amp; closing the accordion&lt;/h2&gt;
&lt;p&gt;Accordion animation techniques seem to be the part that varies the most across implementations. Some animation the height using &lt;code&gt;max-height&lt;/code&gt;, some use JavaScript to actually animate the exact height, some just have the content appear, and some will fade in using a transform and/or opacity. Like all of animation, it nice to be able to customize this to fit with the overall approach of a given project.&lt;/p&gt;
&lt;p&gt;My preference is to use JavaScript to animate the exact height. This is a little heavier than a pure CSS approach, but offers the best experience. Someday, it would be lovely if this sort of thing was built into the browser, but given all of the different approaches, this is probably nearly impossible to pull off.&lt;/p&gt;
&lt;p&gt;Of note, I took the core of the upcoming functions from &lt;a href=&quot;https://www.brandons.me&quot;&gt;Brandon Smith&lt;/a&gt;, through his &lt;a href=&quot;https://codepen.io/brundolf/pen/dvoGyw&quot;&gt;CodePen&lt;/a&gt; and the &lt;a href=&quot;https://css-tricks.com/using-css-transitions-auto-dimensions/&quot;&gt;associated CSS-Tricks article&lt;/a&gt; discussing transitions on auto dimensions. I love a concise demonstration of a concept, it helped me easily understand how this could be accomplished, which then made it easier to adjust as needed. Thanks Brandon!&lt;/p&gt;
&lt;p&gt;Starting with a function to open the accordion, we pass in the accordion element itself, along with the child elements we defined earlier in an object, &lt;code&gt;elements&lt;/code&gt;. First, it gets the height of the accordion content, using &lt;code&gt;.scrollHeight&lt;/code&gt;. This works even though the element is currently not visible. It then applies that height to the element. This gives us something to animate to.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const openAccordion = (accordion, elements) =&amp;gt; {
  const contentHeight = elements.content.scrollHeight

  elements.content.style.height = contentHeight + &apos;px&apos;
  elements.content.addEventListener(&apos;transitionend&apos;, function(){
    elements.content.removeEventListener(&apos;transitionend&apos;, arguments.callee)
    elements.content.style.height = &apos;auto&apos;
  })

  accordion.classList.add(&apos;is-active&apos;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, it adds an event listener to fire when the transition has completed. When this happens, the height of the content is fully opened. It then removes itself and sets the height of the content to &lt;code&gt;auto&lt;/code&gt;. This allows for the page to be resized without cutting off any content or causing side effects. Last, it applies a class of &lt;code&gt;is-active&lt;/code&gt; to the accordion container for styling.&lt;/p&gt;
&lt;p&gt;To accompany this, some styles are needed. The height needs to be set to &lt;code&gt;0&lt;/code&gt; by default, with the overflow hidden, and a transition added for the open and close animation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.accordion-content {
  overflow: hidden;
  transition: height 0.3s cubic-bezier(0.65, 0.05, 0.36, 1);
  height: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, the close function, which will peform the same actions in reverse. The biggest difference here is the use of &lt;code&gt;requestAnimationFrame()&lt;/code&gt;, which ensures that we get a smooth animation. First, all CSS transitions are disabled, then the height is once again set on the accordion content, and then it is transitioned to a height of zero.&lt;/p&gt;
&lt;p&gt;Where we previously set the height to zero after the animation completed, this time we wait for it to complete before removing the active class. This prevents the closed state from appearing for the user before it has actually closed.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const closeAccordion = (accordion, elements) =&amp;gt; {
  const contentHeight = elements.content.scrollHeight
  const elementTransition = elements.content.style.transition
  elements.content.style.transition = &apos;&apos;

  requestAnimationFrame(() =&amp;gt; {
    elements.content.style.height = contentHeight + &apos;px&apos;
    elements.content.style.transition = elementTransition
    requestAnimationFrame(() =&amp;gt; {
      elements.content.style.height = 0 + &apos;px&apos;
    })
  })

  accordion.addEventListener(&apos;transitionend&apos;, function(){
    accordion.removeEventListener(&apos;transitionend&apos;, arguments.callee)
    accordion.classList.remove(&apos;is-active&apos;)
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;And that’s it! Super simple! Okay, fine, not really. It’s difficult, and I worked on this for weeks. There are probably things I’m missing, or things I’ll change in a month or two, but it’s a good place to be for now. You can see the full script in the &lt;a href=&quot;https://github.com/samhermes/alexander/blob/main/src/js/components/accordion.js&quot;&gt;accordion component of Alexander&lt;/a&gt;, a front-end starter kit I created.&lt;/p&gt;
</content:encoded></item><item><title>How the web saved and failed us</title><link>https://samhermes.com/posts/how-the-web-saved-and-failed-us/</link><guid isPermaLink="true">https://samhermes.com/posts/how-the-web-saved-and-failed-us/</guid><pubDate>Sat, 14 Aug 2021 16:50:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve been intrigued by the role that the web played during the pandemic, so it&apos;s high time to reflect on the good and the bad.&lt;/p&gt;
&lt;p&gt;Naturally, this is my own perspective, and I have little to no hard data to go off of for much of this. The pandemic brought a lot of our lives into alignment, but also created stark contrasts. I am certainly aware of my privilege through this time.&lt;/p&gt;
&lt;p&gt;Also, I am looking specifically at the web, experienced through browsers. Naturally, apps played just as significant a role as the web, but I&apos;m a web developer. I&apos;m most interested in what was good and bad about the web, and how we might use that going forward. Plus, the web is better.&lt;/p&gt;
&lt;h2&gt;News and information&lt;/h2&gt;
&lt;p&gt;This, to me, is the area of most interest. In so, so many ways, we failed. I don&apos;t think that this was a failing of the web itself, but rather how we publish to it, and the incentives at play. It&apos;s sort of terrifying to think that we primarily made our way through on clickbait. Stemming from this, I think where we failed most was clarity. The internet is such a noisy place, with &lt;a href=&quot;https://www.youtube.com/watch?v=k1BneeJTDcU&quot;&gt;everyone posting everything all the time&lt;/a&gt;. It felt as if things were popping up completely at random. The CDC was maintaining up to date guidelines, but I never personally looked at them for some reason (hmm, no idea why). Using &lt;a href=&quot;http://archive.org/&quot;&gt;archive.org&lt;/a&gt;, we can watch how they changed over time, such as &lt;a href=&quot;https://web.archive.org/web/20200328172009/https://www.cdc.gov/coronavirus/2019-ncov/prevent-getting-sick/prevention.html&quot;&gt;this example from March 28&lt;/a&gt; where they were still only recommending a face mask if you were sick and emphasizing &lt;a href=&quot;https://www.theatlantic.com/ideas/archive/2020/07/scourge-hygiene-theater/614599/&quot;&gt;hygiene theater&lt;/a&gt;. Where were we supposed to look?&lt;/p&gt;
&lt;p&gt;Adding to the noise, &lt;a href=&quot;https://www.harvard.edu/coronavirus/&quot;&gt;everyone&lt;/a&gt; &lt;a href=&quot;https://coronavirus.illinois.gov/&quot;&gt;had&lt;/a&gt; &lt;a href=&quot;https://www.chipotle.com/covid19&quot;&gt;to&lt;/a&gt; &lt;a href=&quot;https://www.meijer.com/covid19response.html&quot;&gt;publish&lt;/a&gt; &lt;a href=&quot;https://corporate.walmart.com/here-for-you&quot;&gt;their&lt;/a&gt; &lt;a href=&quot;https://www.southwest.com/coronavirus/&quot;&gt;own&lt;/a&gt; &lt;a href=&quot;https://www.barnesandnoble.com/h/customer-update-on-covid-19&quot;&gt;set&lt;/a&gt; &lt;a href=&quot;https://www1.nyc.gov/site/coronavirus/index.page&quot;&gt;of&lt;/a&gt; &lt;a href=&quot;https://stories.starbucks.com/press/2020/what-customers-need-to-know-about-starbucks-response-to-covid-19/&quot;&gt;guidelines&lt;/a&gt; (can&apos;t wait for those links to break). By and large, the same guidelines applied, no matter where you went, so the overwhelming amount of /covid-19 webpages were just noise. I read none of them, even for places I did go. Some even created entire websites dedicated to it, which is so overwhelming. Many of these seemed to be references for the few people who needed to know (basically internal communication) and marketing fluff to show people that they still cared about taking their money.&lt;/p&gt;
&lt;p&gt;On the other hand, what a great relief it was to have the latest information available. In hindsight, I did not need to follow along nearly as closely as I did, but the internet made it possible to be very up to date. I checked the news throughout the workday, then came home and watched TV news with my parents and heard about all of the things that I&apos;d already read, some of them already out of date. I felt as though I had the best information I could, something only possible because of the internet. It was also incredibly easy to do research. If one source posted something I hadn&apos;t heard before, I looked to see if anyone else was talking about it. This is not enough, but better than relying on the &lt;a href=&quot;https://www.npr.org/sections/thetwo-way/2018/04/02/598794433/video-reveals-power-of-sinclair-as-local-news-anchors-recite-script-in-unison&quot;&gt;scripts that TV news feed us&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, communication was good and bad, but the biggest issue was that many people were too busy trying to survive to keep completely informed. It should have been dead simple for them to do so, and while our leadership was the main problem with this, we still have trouble relaying only the most important message on the web. News websites always have the same level of information density, and are available 24/7. Social media feeds never have quieter times and louder times. Email newsletters, news podcasts, etc all come out every single day. There&apos;s money in being always on, which doesn&apos;t translate into usefulness.&lt;/p&gt;
&lt;h2&gt;Ordering food and groceries&lt;/h2&gt;
&lt;p&gt;I don&apos;t feel I need to give too much background here, I think it&apos;s amazing how quickly local restaurants were able to shift to taking online orders. It seemed, very quickly, that everyone was running on Square or other platforms. This speed was specifically made possibly because of the web. No one could have spun up an iOS and Android app quickly enough.&lt;/p&gt;
&lt;p&gt;Plenty of chain restaurants had mobile order apps before this, which makes sense for their scale, but it still doesn&apos;t make sense for a single location restaurant to waste time and money on an app.&lt;/p&gt;
&lt;p&gt;As for ordering groceries, it was much rockier. Some grocery chains had infrastructure in place beforehand, some of which were ready to go, some of which were not. In the case of groceries, browsing the selection is typically done most comfortably on a larger screen. Issues arose here with the handoff to a mobile device, bringing the tension between web and app to the forefront. Place the order on the web, but let them know you&apos;ve arrived on the mobile app? Not so easy.&lt;/p&gt;
&lt;p&gt;The downside of much of this, whether it was Square, ToastTab, Instacart, or what have you, was that this served to further funnel money to tech companies and away from local economies. Square, naturally, is &lt;a href=&quot;https://squareup.com/us/en/press/making-change-4&quot;&gt;thrilled by this trend&lt;/a&gt; (emotion added by me). I&apos;m not sure that we should start spinning up local bespoke platforms, but it&apos;s a shame that we continue to find new ways of exporting money from small towns.&lt;/p&gt;
&lt;h2&gt;Shopping&lt;/h2&gt;
&lt;p&gt;While it might feel like everyone was shopping online in the last year, they weren&apos;t. Most people were still purchasing goods in store, but this varied greatly by industry. Overall, however, e-commerce use &lt;a href=&quot;https://www2.census.gov/retail/releases/historical/ecomm/21q1.pdf&quot;&gt;quickly trended upward&lt;/a&gt;. This seems to have accelerated a trend that was already growing. Like groceries, this brought the issues to the front. For clothing, &lt;a href=&quot;https://medium.com/@themakers/fashion-e-commerce-s-fitting-problem-e4f3a138484d&quot;&gt;people like trying things on to check color and fit&lt;/a&gt;. For furniture, it&apos;s nice to feel the fabric, sit in the chair, check the color. Or, at base level, it&apos;s nice to know how big something is, something that continues to be ignored by most sellers.&lt;/p&gt;
&lt;p&gt;I think, more than ever, we were aware of our local shops. Hearing that some were in danger of disappearing forever, we recommitted to buying books from local bookshops, also made possible by the web. Like ordering food, this required depending very heavily on platforms. Bookshop.org had barely gotten themselves going by the time the pandemic started and &lt;a href=&quot;https://www.fastcompany.com/90610596/how-bookshop-helped-independent-bookstores-make-it-through-the-pandemic&quot;&gt;their business skyrocketed&lt;/a&gt;. I would not have wanted to be on call to keep those servers running. Shops that had this infrastructure in place beforehand, like restaurants that did, were best positioned, but it was the web that made it possible for everyone else to come online quickly.&lt;/p&gt;
&lt;p&gt;Of course, I must mention the global supply chain, as well as the &lt;a href=&quot;https://www.theguardian.com/technology/2020/nov/18/how-amazon-became-a-pandemic-giant-and-why-that-could-be-a-threat-to-us-all&quot;&gt;workers who make it possible&lt;/a&gt;. We are still running low on some items, and worker conditions are still bad. Largely, this experience has pulled the curtain back. Through eCommerce, it’s easier than ever to sling something around the planet, without awareness of what it takes to make it happen. It seemed magical before, but the &lt;a href=&quot;https://www.cnn.com/2021/06/03/tech/amazon-dsp-delivery/index.html&quot;&gt;cost of that magic&lt;/a&gt; may be more than any of us really wants to pay.&lt;/p&gt;
&lt;h2&gt;Google heat map&lt;/h2&gt;
&lt;p&gt;I haven&apos;t heard stats on usage of this, but I found myself using &lt;a href=&quot;https://blog.google/products/maps/maps101-popular-times-and-live-busyness-information/&quot;&gt;Google&apos;s &quot;live busyness&quot; graphs&lt;/a&gt; to determine if locations were busy. Before heading to the grocery store, I would check to see if it was having a particularly busy day. Simply searching for a location usually shows you the graph, sometimes higher up on the page, sometimes further down.&lt;/p&gt;
&lt;p&gt;In general, I used it to see when places were less busy, which, unsurprisingly were on weekdays and close to closing time. I often made my trips on weeknights around 7 or 8pm. I&apos;m not sure if the graphs were actually useful, but it did feel like at least something to reference. I was definitely too worried in general, though.&lt;/p&gt;
&lt;p&gt;While we&apos;re here, worth mentioning that these graphs are made possible by Google&apos;s mass surveillance of their users, and while the article linked above mentions their technique for keeping this data private, it still demonstrates just how much data we&apos;re handing over to tech companies. That is, of course, just the tip of the iceberg, as &lt;a href=&quot;https://twitter.com/TectonixGEO/status/1242628347034767361&quot;&gt;we found out from spring breakers in Florida&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The DMV&lt;/h2&gt;
&lt;p&gt;I had to go to the DMV during the pandemic and watched through the plexiglass as someone filled out a form on a website for me. That&apos;s all I&apos;m going to say about that.&lt;/p&gt;
&lt;h2&gt;Escapism&lt;/h2&gt;
&lt;p&gt;At various points during the pandemic, I turned to YouTube to watch videos of people going about things in the real world from the past. It was strange, a mix of escape, imagining the world as it once was, but also was a bit too much of a reminder of what limitation we were living under. I think YouTube&apos;s affect on society goes under the radar too frequently, but it feels like the most prominent mirror (of the good and bad) that we have. Being able to rewind the mirror was interesting, at the very least.&lt;/p&gt;
&lt;p&gt;Worth mentioning here is the broader video via web landscape, as its usage increased. While app usage didn&apos;t change too much, &lt;a href=&quot;https://www.nytimes.com/interactive/2020/04/07/technology/coronavirus-internet-use.html&quot;&gt;web usage dramatically increased for Netflix, YouTube, and Twitch&lt;/a&gt;. I don&apos;t want to assume too much about everyone else here, but my usage of these services increased, and helped regulate my emotions. I revisited movies I hadn&apos;t seen in a long time, I watched series that weren&apos;t too challenging, and, as I mentioned, escaped into the past on YouTube. These are all, of course, mixes of app, TV, and web usage, but I think the trends we saw are a good indication that cross-platform solutions are important and we shouldn&apos;t assume a single platform will work (cough, Quibi).&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;So, what does all this mean? I don’t know that a single north star has appeared from all of this chaos, but I think it points to the continued necessity of the flexibility of the web as a platform. We must protect its openness, it’s accessibility, and continue to make things easier to use. We need to bring more people online, increase their connection speeds, and make sure that they can reap the benefits. We need to protect privacy, give people the option to opt out of being tracked, and work on more sustainable business models. Lastly, we need to make sure that the web remains a blank slate, where anyone can join. Where we can connect, support, entertain, learn, and make tomorrow better.&lt;/p&gt;
</content:encoded></item><item><title>I&apos;m overly optimistic when estimating time</title><link>https://samhermes.com/posts/im-overly-optimistic-when-estimating-time/</link><guid isPermaLink="true">https://samhermes.com/posts/im-overly-optimistic-when-estimating-time/</guid><pubDate>Thu, 13 May 2021 02:23:00 GMT</pubDate><content:encoded>&lt;p&gt;I mean, who isn’t!? I wanted to pull at this string a little though, to see what’s there. I&apos;ve been finding myself setting expectations that are sunnier than they should be for years now, and then I deal with the pain of attempting to deliver on a promise that stretches me too thin.&lt;/p&gt;
&lt;p&gt;First, people pleasing. I like to say yes, I like to agree, I like to give reassurance. It feels nice in the moment, but in a team setting, it’s not so functional. Not only am I setting myself up for more stress, I’m passing that on to others when the delivery date starts slipping. My optimism turns sour, and then that hurts more than it would if I had set expectations.&lt;/p&gt;
&lt;p&gt;Second, the art of time estimation. Even for someone who has more realistic planning senses, it’s hard to estimate time. Most things take longer than you might think, due to hidden complexity. I’m coming at this from the perspective of development, but it’s true about many things. I think, sure, I’ll do all my laundry today, but I didn’t look into it enough to realize that it’s actually 4 loads. I can always do half today and half tomorrow.&lt;/p&gt;
&lt;p&gt;Third, a little more about hidden complexity. Software is hard. Even things that are not tangled in spaghetti code are still pretty spaghetti. Maybe you’re thinking about the code you’re going to work on, but when your build tool does that thing where it’s a build tool, it can mess up your plan pretty quickly. It just doesn&apos;t take much to get things headed off course, and sometimes it&apos;s not anyone&apos;s fault.&lt;/p&gt;
&lt;p&gt;In general, I feel like this is one of those things that you just have to work on by yourself. It wasn’t taught in business school, no one is going to come help me work through this, it’s just something I need to practice. So, how does one go about that? I’m going to try not to be too optimistic about how quickly I can course correct…&lt;/p&gt;
&lt;h2&gt;Add 20%?&lt;/h2&gt;
&lt;p&gt;This feels like too generic of an answer. It might be a good thing to pilot though. Maybe try it out, see how it helps. Apply it in scenarios where it seems useful. Also, round numbers. It’s a good tool because of rememberability.&lt;/p&gt;
&lt;h2&gt;The more you know&lt;/h2&gt;
&lt;p&gt;This one is pretty simple. If you know more about what the work is, you can make a better estimate. If there are only one or two unknowns, you can be fairly confident about the rest. For this to work, I think I would need to be more honest and upfront, to say, “I need more information” or “I need some time to look into this” before giving an estimate. That can be frustrating, but I sometimes skip this step, or convince myself that I&apos;m well informed enough.&lt;/p&gt;
&lt;h2&gt;Look back&lt;/h2&gt;
&lt;p&gt;I think it would really help me to look back over my estimations after the fact, to see just how far I was off. This would actually help me learn about what kinds of things I often estimate incorrectly, or at least give me a baseline of how much of a problem this is. Typically, when I give an estimate, there&apos;s no system to close that loop, so I&apos;ve been missing out on those learning experiences. Again, not something anyone else is going to do for me.&lt;/p&gt;
&lt;h2&gt;Stress&lt;/h2&gt;
&lt;p&gt;Before I wrap this up, I have to address stress. I think it&apos;s a major factor here. Especially with what we&apos;ve all been through. Some days, it&apos;s all gotten to me. I&apos;m not productive on those days. I wish I wasn&apos;t expected to be productive on those days. Usually, when I&apos;m estimating time, I&apos;m envisioning myself as operating at 100%. Again, optimism. No one is operating at that level all the time, and if they are, they need to take a break. Being realistic about how much I should push myself is something that no one else will do for me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update, May 23, 2021:&lt;/strong&gt; I just came across &lt;a href=&quot;https://fs.blog/2021/05/slack/&quot;&gt;this article from Farnam Street&lt;/a&gt; about the necessity of slack time. I agree with what the article is saying, but in practice, this burden is still placed on the individual. An organization would need to recognize, at all levels, the need for slack, something near impossible to pull off. Still, a good idea to carry with me as I estimate time.&lt;/p&gt;
</content:encoded></item><item><title>Disable inline image option in Gutenberg</title><link>https://samhermes.com/posts/disable-inline-image-option-in-gutenberg/</link><guid isPermaLink="true">https://samhermes.com/posts/disable-inline-image-option-in-gutenberg/</guid><pubDate>Thu, 17 Dec 2020 04:53:00 GMT</pubDate><content:encoded>&lt;p&gt;In Gutenberg, several core blocks include the option to insert an inline image. This is not an image float, but rather an image, literally, inline. It works anywhere that RichText is used, so headings, paragraphs, lists, buttons, all include this ability. If used properly, this is fine. It&apos;s valid HTML. However, it is an aesthetic disaster.&lt;/p&gt;
&lt;p&gt;Confusingly, this inline image option is called a &quot;format&quot; in the Gutenberg code, which only makes sense when you see that it&apos;s grouped with bold, italic, etc. RichText includes a RichTextToolbar, where these options are presented to the user. All of this makes it rather difficult to search and find a proper solution, so it took me a while to unearth this.&lt;/p&gt;
&lt;p&gt;To disable any of the formats available in the RichTextToolbar, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wp.richText.unregisterFormatType(&apos;core/image&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I wish that options like these were easier to disable, or just easier to learn how to disable. The option above applies to all blocks, which is unfortunate, as the most ideal situation here would be the ability to disable block-by-block. Now, if we could just get rid of the block radius setting.&lt;/p&gt;
</content:encoded></item><item><title>Analytics: Where do we go?</title><link>https://samhermes.com/posts/analytics-where-do-we-go/</link><guid isPermaLink="true">https://samhermes.com/posts/analytics-where-do-we-go/</guid><pubDate>Thu, 10 Sep 2020 21:10:00 GMT</pubDate><content:encoded>&lt;p&gt;Measuring web traffic on the web. Yikes. Right now, it seems like we are in a precarious place, increasingly so. With privacy becoming more and more of a household topic, how should we think about collecting analytics in the coming years? (Spoiler alert: I do not have the answer. But, definitely thinking about it.)&lt;/p&gt;
&lt;p&gt;Previously, attaching Google Analytics to a site seemed like a fairly obvious choice. It was, and still is, a big priority for Google, and it’s essentially the only viable choice. Now, it doesn’t seem so obvious.&lt;/p&gt;
&lt;p&gt;In the past, on many of my projects, I’ve hooked up Google Analytics and gone on with my life. It turns out, in hindsight, that many of these only needed a small snapshot of recent data, and that it was far more convenient to view this data through the site’s admin, WordPress. All of the other data that Google Analytics was collecting was, largely, just for Google. Seems like I should get a commission. In fact, we all should. 👀&lt;/p&gt;
&lt;p&gt;Every time that I go dig into the ills of data collection, things seem darker and darker. My simple act of adding to Google’s data treasure trove seems less and less innocent all the time. I have no malicious intent, my goal has simply been to install some mechanism by which site owners can know how their site is performing. It’s unfortunate that this is tied to a large corporation gaining more access to our whereabouts.&lt;/p&gt;
&lt;h2&gt;Alternatives to Google Analytics&lt;/h2&gt;
&lt;p&gt;A fairly good route to go is just with something other than Google Analytics. There are all kind of companies that have cropped up over recent years. I’ve tried out StatCounter, and there are other products like Clicky, Matomo, or GoSquared. Most of these offerings have a limit on how much you can get for free. With StatCounter, it only keeps so much data. Clicky has a limit on daily page views.&lt;/p&gt;
&lt;h2&gt;Ad Blockers&lt;/h2&gt;
&lt;p&gt;Even if you pick a super-privacy-concious analytics service, your efforts could be thwarted by ad blockers. It’s a bit difficult to know how many people have these installed, especially if the ad blockers are doing their job properly. Statista reports that 26% of users have one running this year, but it’s hard to know how accurate this is. Other sites that I viewed reported different numbers.&lt;/p&gt;
&lt;p&gt;As ad blockers also block tracking scripts, the data that we collect will always be wrong. To what degree, it’s hard to say. A more technical site likely has a higher percentage of users with ad blockers. An e-commerce site might be more middle of the road, but is still misreporting.&lt;/p&gt;
&lt;h2&gt;Server Statistics&lt;/h2&gt;
&lt;p&gt;Here’s another location where we could potentially get an idea of how much traffic a site is getting. This is full of issues as well, naturally. Due to caching, either on the site itself or in the user’s browser, some users will never hit the server. There’s also the traffic of the various bots that roam the internet, which will show up as a request alongside other users. Getting a good picture of what’s a real visit and what’s not is difficult, and the server doesn’t collect much in the way of user data&lt;/p&gt;
&lt;h2&gt;Where do we go?&lt;/h2&gt;
&lt;p&gt;I wish I had the answer to this question. I hope you didn’t expect an answer here. This is a really complex topic. For now, it seems like the best approach would be to install an alternative to Google Analytics. Which of these to choose is difficult, but those that are built on privacy seem to be a good place to start. If you can pay for an analytics service, that seems like the best option.&lt;/p&gt;
&lt;p&gt;Long term, we have two very contradictory needs, the need for user privacy, and the need for an individual or organization to measure their reach. On their own, these are very reasonable. But together, they only become more and more important. As more of what we do moves online, the more we need to measure. The more that we use the web, the more important it is that we are able to move around without being followed.&lt;/p&gt;
</content:encoded></item><item><title>Are progressive web apps important?</title><link>https://samhermes.com/posts/are-progressive-web-apps-important/</link><guid isPermaLink="true">https://samhermes.com/posts/are-progressive-web-apps-important/</guid><pubDate>Fri, 04 Sep 2020 21:37:00 GMT</pubDate><content:encoded>&lt;p&gt;As part of Google’s Lighthouse tool (which is very useful), it gives feedback on how well a site has implemented progressive web app (PWA) features. It’s one of five main measurements, alongside performance and accessibility. Google has championed progressive web apps more than anyone, so it isn’t surprising that the ranking gets this positioning in its own tool. However, how important are they?&lt;/p&gt;
&lt;p&gt;Spelled out right in the name is “web app,” which already gives an eye into when PWAs might be useful. When your site contains app-like behavior (I’ll let you make the call on that one), it makes sense that you might work to optimize that, and adding PWA features is a great place to start. It allows developers to store important assets on the user’s device, so that the next interaction is super fast.&lt;/p&gt;
&lt;p&gt;When we look at the wider web, however, should the general advice be to make your site into a progressive web app, no matter what?&lt;/p&gt;
&lt;h2&gt;Generalizations about the web&lt;/h2&gt;
&lt;p&gt;A newcomer to web development would not be blamed for thinking that web development is mainly about libraries and frameworks, as this is what gets talked about most frequently. React, Vue, etc. catch most of the headlines. Those frameworks do have a lot of figuring out to do in their quest to re-implement the web inside of itself, so it makes sense that there is so much chatter [end snark]. However, it can distort the reality of what the web is actually made up of.&lt;/p&gt;
&lt;p&gt;For e-commerce sites, social networking sites, dashboards, tools, things of that sort, JavaScript is absolutely required, and the usual tools for these applications now come with progressive web app functionality bundled in. If you use Create React App to start a React project, it includes the needed stuff to make your application a progressive web app out of the box.&lt;/p&gt;
&lt;p&gt;If you’re making a blog, or a marketing site, or really anything that’s not an “app,” you probably don’t need to bother implementing the PWA features. It’s a waste of time, stores assets on your users device unnecessarily, causes them to download extra unnecessary files the first time they visit your site, and is an extra burden on already overburdened developers.&lt;/p&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;For a web app, the typical expectation is that users will visit again and again. A social media service expects repeat visits, an enterprise tool could be used day in and day out. Progressive web apps are able to store many of the app’s assets locally on the users device, and just grabs them from local storage instead of sending a network request. That really speeds up the application. Performance win.&lt;/p&gt;
&lt;p&gt;Will you return to a marketing site day after day? Probably not. What if you’re using a search engine, and hitting lots of different sites as you look for an answer? You don’t want to keep any of the assets from those sites. For those sites to do any extra work to speed up your second visit is a waste.&lt;/p&gt;
&lt;h2&gt;Offline&lt;/h2&gt;
&lt;p&gt;Another great perk of progressive web apps is that you can allow a user to still interact with the app while they are offline. You could even show a custom “you’re offline” message when they are offline. I just… don’t know why this is useful in any way. If something lives on the web, it needs a connection. A user’s device is already good at communicating when the connection has been broken. And, if I’ve lost my connection, I probably don’t want to try to do anything with an app anyway. I have to trust that everything gets properly sorted out when the connection comes back.&lt;/p&gt;
&lt;h2&gt;Installable&lt;/h2&gt;
&lt;p&gt;This topic is heavily influenced by our favorite trillion dollar corporation, as iOS has really been the main holdup on installable web apps gaining hold. Despite some sort of progress (?) on this in the last few years, it’s still very clear that Apple wants to keep their very profitable App Store humming along. PWAs on iOS are just buggy enough to be useless.&lt;/p&gt;
&lt;p&gt;Google’s great improvements in Android have been remarkable, and I wish that iOS could match it. Without wide cross-platform adoption of the features of PWAs, I can’t see this being a compelling reason to implement any of them. This is true of anything on the web. Do we suggest users on Android install a web app, and then users on iOS have to download a native app? This is a strange fracturing.&lt;/p&gt;
&lt;h2&gt;Are PWAs important?&lt;/h2&gt;
&lt;p&gt;Back to the original question. The answer, of course, is nuanced. But, for many developers, PWAs are not important. If a project is “app-like,” it deserves some consideration, naturally, based on user trends and plenty of real-world testing, like anything else. It’s important that we implement features that make a difference to the user experience, not just because an internet giant is giving us a pass/fail.&lt;/p&gt;
</content:encoded></item><item><title>My WordPress hosting recommendation</title><link>https://samhermes.com/posts/my-wordpress-hosting-recommendation/</link><guid isPermaLink="true">https://samhermes.com/posts/my-wordpress-hosting-recommendation/</guid><pubDate>Fri, 28 Aug 2020 19:14:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been making hosting recommendations to clients for a while now, and it’s honestly been a bit of a journey. With so many options, there are a lot of good paths, and some paths that you just have to go down for a while before you really know. It would probably be useful to list those paths, but I’m going to just focus on the path that has been the most sensible to me.&lt;/p&gt;
&lt;p&gt;Some caveats about this recommendation, first. This is for moderately trafficked sites that do not require any special levels of security. I’m also coming at this, naturally, thinking about WordPress. This is my WordPress hosting recommendation, after all. I’m really just sharing my personal perspective based off of past experiences with a variety of popular hosts.&lt;/p&gt;
&lt;h2&gt;Dreamhost&lt;/h2&gt;
&lt;p&gt;My recommendation for WordPress hosting is Dreamhost. This isn’t a crazy suggestion, &lt;a href=&quot;https://wordpress.org/hosting/&quot;&gt;WordPress.org itself recommends it&lt;/a&gt;. However, I will not say anything about the others on that list, which… um, is still saying something. I have had the best overall experience with Dreamhost, and really appreciate their support of WordPress, from core contributions to community involvement.&lt;/p&gt;
&lt;h3&gt;Ease of use&lt;/h3&gt;
&lt;p&gt;WordPress hosting is, for the most part, WordPress hosting. There’s a server, there are files, you point a domain at it. So, as is true with so many things nowadays, the software layer on top is what makes the difference. This is probably the most subjective of all my reasons.&lt;/p&gt;
&lt;p&gt;I like the simplicity of the control panel. There’s a sidebar with everything associated with your account, the domain, hosting, databases, SSL certificates, billing, etc. So many other hosts have many different views for all of this, and then change or rearrange things often.&lt;/p&gt;
&lt;h3&gt;Pricing&lt;/h3&gt;
&lt;p&gt;Dreamhost’s WordPress hosting is priced really competitively. Currently, if you sign up for 1 year, it includes a domain and an SSL certificate for $3.95/mo. That’s a great deal for most people.&lt;/p&gt;
&lt;h3&gt;SSL Certificate&lt;/h3&gt;
&lt;p&gt;With Dreamhost, the SSL certificate is included for free. With Let’s Encrypt, the expectation is that these certificates just come out of the box. Somehow, as of writing, GoDaddy is still charging customers $80/year for SSL certificates.&lt;/p&gt;
&lt;h3&gt;Support&lt;/h3&gt;
&lt;p&gt;This is one that can be make-or-break for some people. Dreamhost offers no phone support. As an introvert, this is fine with me. I have worked with their support team on a few occasions (don’t often need them!), and they’ve been very prompt and helpful.&lt;/p&gt;
&lt;h3&gt;Managed WordPress&lt;/h3&gt;
&lt;p&gt;There’s an ever-growing market of “Managed WordPress” offerings on the market now, which offer a more streamlined experience, better security and performance, and nice additions like staging sites. In some instances, this kind of package is far more appropriate for the job. Dreamhost has packages for this too, but they don’t seem to rank as often as those from Kinsta, WP Engine, and Flywheel.&lt;/p&gt;
</content:encoded></item><item><title>What is product management?</title><link>https://samhermes.com/posts/what-is-product-management/</link><guid isPermaLink="true">https://samhermes.com/posts/what-is-product-management/</guid><pubDate>Sat, 06 Jun 2020 15:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been interested in exploring the practice of product management, as it’s something that I think I do a bits and pieces of in my current role. I think that it’s worth digging in to this, to see if it would be a useful frame for me as I go about my current work, and if it’s something I would like to more intentionally lean into in the future.&lt;/p&gt;
&lt;p&gt;To start, &lt;a href=&quot;https://en.wikipedia.org/wiki/Product_management&quot;&gt;Wikipedia gives us this definition&lt;/a&gt;: “Product management is an organizational function within a company dealing with new product development, business justification, planning, verification, forecasting, pricing, product launch, and marketing of a product or products at all stages of the product lifecycle.”&lt;/p&gt;
&lt;p&gt;That’s a lot of stuff! Way more than one person can handle. We’re going to need to dig a little deeper into this to really see what aspects are product management and what are really the duty of other disciplines. Overall, from my research, the definition varied greatly. This is still a relatively new role (&lt;a href=&quot;https://www.atlassian.com/agile/product-management/product-manager&quot;&gt;in software, at least&lt;/a&gt;), and, a role that varies greatly from organization to organization.&lt;/p&gt;
&lt;p&gt;Although a bit rudimentary, I want to start at a low level.&lt;/p&gt;
&lt;h2&gt;What is a product?&lt;/h2&gt;
&lt;p&gt;Quite a while ago now, when I first heard of people working at big tech companies as “product designers,” I was confused. The word &lt;em&gt;product&lt;/em&gt; hadn’t yet been applied to software in my experience; it made me think of physical goods. Really, the word product is incredibly generic. &lt;a href=&quot;https://www.dictionary.com/browse/product&quot;&gt;Dictionary.com gives us&lt;/a&gt; “a thing produced by labor.” So, there you go. Products are almost everything.&lt;/p&gt;
&lt;p&gt;The word product, to me, brings to mind the word “packaging,” and I think that those two words together are, pardon me, products of the human desire to put things at boxes. A product, in the marketplace, has a pretty well defined beginning and end, and we package it up to make it easy to market, sell, ship, place, etc. Same with software. A software product naturally comes to have walls around it, and, as we can see with &lt;a href=&quot;https://www.npmjs.com&quot;&gt;npm&lt;/a&gt;, make it easier to distribute.&lt;/p&gt;
&lt;p&gt;If products are the things produced by labor, we are making all kinds of products inadvertently. Companies usually give priority to a set of these products, and encourage resources be directed towards them. Whether or not we actually say “product,” we do say what is and isn’t important. Some of these products are for consumers, some are for internal teams, some are for research. The more important these products are, the more important it is that we approach them with thought and care.&lt;/p&gt;
&lt;h2&gt;What do product managers do?&lt;/h2&gt;
&lt;p&gt;Sherif Mansour of Atlassian has &lt;a href=&quot;https://www.atlassian.com/agile/product-management/product-manager&quot;&gt;a great article about the product manager role&lt;/a&gt;, and offers this list of responsibilities:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Understanding and representing user needs.&lt;/li&gt;
&lt;li&gt;Monitoring the market and developing competitive analyses.&lt;/li&gt;
&lt;li&gt;Defining a vision for a product.&lt;/li&gt;
&lt;li&gt;Aligning stakeholders around the vision for the product.&lt;/li&gt;
&lt;li&gt;Prioritizing product features and capabilities.&lt;/li&gt;
&lt;li&gt;Creating a shared brain across larger teams to empower independent decision making.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;In a more simplified sense, it’s about taking in a lot of good information, processing that, and then giving it to the team in meaningful and helpful ways. Are we hitting the mark with what we’re doing? Could we be better? How do we get there? Is there something that the team can’t see from their point of view?&lt;/p&gt;
&lt;p&gt;When I think about the responsibilities from above in the context of my current team, they are currently divided up between a number of different people. Rolling them all up into one role allows them to have special focus. (Isn’t this the case with almost all roles? Dare I say that us web people are all the result of thoughtfully breaking apart the webmaster role?)&lt;/p&gt;
&lt;p&gt;As we learn that the product manager has their finger on almost all aspects of the product, it’s grounding to remember that “product managers simply don’t have any direct authority over most of the things needed to make their products successful,” &lt;a href=&quot;https://www.mindtheproduct.com/product-managers-not-ceo-anything/&quot;&gt;according to Martin Eriksson&lt;/a&gt;, and, upon reflection, this makes perfect sense. They are not executing on their plans, nor are they the overall team lead. They bring, &lt;a href=&quot;https://www.mindtheproduct.com/product-managers-not-ceo-anything/&quot;&gt;to quote Martin Eriksson again&lt;/a&gt;, &quot;everyone together around a shared understanding of the customer problem,” and then they step aside.&lt;/p&gt;
&lt;p&gt;In a very broad sense, from &lt;a href=&quot;https://medium.com/@bfgmartin/what-is-a-product-manager-ce0efdcf114c&quot;&gt;this article&lt;/a&gt; quoting &lt;a href=&quot;https://svpg.com/inspired-how-to-create-products-customers-love/&quot;&gt;Marty Cagan’s book&lt;/a&gt; &lt;a href=&quot;https://svpg.com/inspired-how-to-create-products-customers-love/&quot;&gt;&lt;em&gt;Inspired&lt;/em&gt;&lt;/a&gt;, a product manager’s goal is &quot;to discover a product that is valuable, usable and feasible.” It’s hard for any one discipline to come to this with a clear head. As a developer myself, I often push for features or plans that make the most sense to me. For a product manager, &lt;a href=&quot;https://medium.com/@bfgmartin/what-is-a-product-manager-ce0efdcf114c&quot;&gt;concerned with UX, business, and tech&lt;/a&gt;, there has to be a practice of making decisions not based on any one discipline. The discipline is product. The focus is users.&lt;/p&gt;
&lt;p&gt;Product managers communicate that “we’re adding x feature because y,” or “we’re not doing x because it’s not worth the time.” These simple statements are really clear and concise, but take a lot of background knowledge to say confidently.&lt;/p&gt;
&lt;h2&gt;How is &lt;em&gt;product&lt;/em&gt; management different from &lt;em&gt;project&lt;/em&gt; management?&lt;/h2&gt;
&lt;p&gt;I work with project managers right now, and they are invaluable. They coordinate all of the volatile pieces of a project in a magical way, and are some of the most adaptable people I know. Where I think we really get to the distinction of the two roles, is that project management work mostly deals with &lt;a href=&quot;https://www.productplan.com/product-management-versus-project-management/&quot;&gt;puzzle pieces that are already in play&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Project managers have lots of inputs, from internal and external sources, and plenty of resources to route these inputs through. What is often lacking here, though, is the ability to make higher level decisions. This is usually good, as it allows them to stay focused on execution. It can be bad, though, if there isn’t someone there to make those higher level, strategic decisions, as things can veer off course rather easily. Product management fills that gap, by thinking about the bigger picture.&lt;/p&gt;
&lt;p&gt;So, in essence, it can be a yin and yang that keeps a team going!&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Overall, through writing this, I feel &lt;em&gt;less&lt;/em&gt; like what I’ve been doing in my recent work is product management. I believe that I initially confused it with project management in some areas, but can more clearly see the distinction. From the list of responsibilities &lt;a href=&quot;https://www.atlassian.com/agile/product-management/product-manager&quot;&gt;provided by Sherif Mansour&lt;/a&gt;, there is a lot more that I could be doing if I wanted to lean into product management.&lt;/p&gt;
&lt;p&gt;The biggest gap that I can see is on the research side. I’d say that this is probably pretty common. It’s difficult to get good data coming in, and keep it coming. The more we know about what users want or need, the better our products are, so this is important to devote resources to. In fact, it feels like this is a critical step one to get the ball rolling. From there, vision, priority, meaning all flow.&lt;/p&gt;
&lt;p&gt;I definitely read a lot about product management to write this, but it still feels like the kind of thing that you have to experience to really know properly. Knowing that it varies from team to team, it seems like a role that needs flexibility. Really focused flexibility. I’m also interested in how this role is influenced by each person who approaches it. To be good, you need to already have an idea of what a good product is, and that will vary person by person. Something to keep chewing over.&lt;/p&gt;
</content:encoded></item><item><title>Using a single stylesheet for both block and classic editor</title><link>https://samhermes.com/posts/using-a-single-stylesheet-for-both-block-and-classic-editor/</link><guid isPermaLink="true">https://samhermes.com/posts/using-a-single-stylesheet-for-both-block-and-classic-editor/</guid><pubDate>Wed, 25 Mar 2020 17:58:00 GMT</pubDate><content:encoded>&lt;p&gt;When I first started working with the block editor, my assumption was that I would need to define a separate set of styles just for the block editor. While this has never been the guidance from core, I was resistant to the idea that I could enqueue my existing editor stylesheet (from the classic editor) and everything would just work. However, now that I’ve revisited this, I may have been wrong!&lt;/p&gt;
&lt;p&gt;Previously, I had maintained an existing &lt;code&gt;editor-style.css&lt;/code&gt; and added a new &lt;code&gt;block-editor-style.css&lt;/code&gt; file. This made sense and kept everything siloed and simple. I used &lt;code&gt;enqueue_block_editor_assets&lt;/code&gt; to enqueue the block editor stylesheet in just the block editor, which worked great.&lt;/p&gt;
&lt;p&gt;The cracks began to show with this when the block editor &lt;a href=&quot;https://make.wordpress.org/core/2020/03/02/markup-and-style-related-changes/&quot;&gt;swapped out many of its existing class names&lt;/a&gt;. In order to ensure that my styles in &lt;code&gt;block-editor-style.css&lt;/code&gt; would override the block editor’s own styles, I wrapped everything in &lt;code&gt;body.block-editor-page&lt;/code&gt; and used &lt;code&gt;.edit-post-layout__content&lt;/code&gt; to further increase specificity. Essentially, in WP 5.4, this meant that most of the styles were no longer being applied.&lt;/p&gt;
&lt;h2&gt;Merging two stylesheets&lt;/h2&gt;
&lt;p&gt;The way that a single stylesheet works is that the block editor transforms some of the editor stylesheet classes. In the &lt;a href=&quot;https://developer.wordpress.org/block-editor/developers/themes/theme-support/#editor-styles&quot;&gt;theme support documentation on this&lt;/a&gt;, it states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“To make sure your styles are applied only to the content of the editor, we automatically transform your editor styles by selectively rewriting or adjusting certain CSS selectors.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As someone who enjoys having control over things, this is a little spooky. “automatically” and “selectively” send shivers down my spine. But, it seems to work pretty well!&lt;/p&gt;
&lt;p&gt;For me, I took all of my &lt;code&gt;block-editor-style.css&lt;/code&gt; styles and copied them into &lt;code&gt;editor-style.css&lt;/code&gt;. I removed &lt;code&gt;.block-editor-page&lt;/code&gt; from the &lt;code&gt;body&lt;/code&gt; selector. I had existing &lt;code&gt;body&lt;/code&gt; styles in my &lt;code&gt;editor-style.css&lt;/code&gt; file, so I merged the two. This didn’t work great. I had previously applied a &lt;code&gt;max-width&lt;/code&gt;, to restrict the width of the content in the classic editor, and that was now messing up the block editor layout.&lt;/p&gt;
&lt;p&gt;To make this work, I added a new style block using the &lt;code&gt;#tinymce&lt;/code&gt; selector. This effectively acted like the previous &lt;code&gt;editor-style.css&lt;/code&gt; stylesheet, and only applied to the classic editor.&lt;/p&gt;
&lt;p&gt;With these changes, I did have to keep some of the “hacking” (as it appears to be) I had done on some of the editor elements. The page/post title, for instance, is still being targeted using the &lt;code&gt;.editor-post-title__input&lt;/code&gt; class name. Will this continue to work? Probably not. Again, the class names &lt;a href=&quot;https://make.wordpress.org/core/2020/03/02/markup-and-style-related-changes/&quot;&gt;just keep changing&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Enqueuing the new stylesheet&lt;/h2&gt;
&lt;p&gt;Figuring out just this part was a little confusing. I was using &lt;code&gt;after_setup_theme&lt;/code&gt; to enqueue the editor stylesheet and a Google font in the classic editor, and then using &lt;code&gt;enqueue_block_editor_assets&lt;/code&gt; to enqueue the block editor stylesheet and, again, a Google font. Turns out, I could just drop the &lt;code&gt;enqueue_block_editor_assets&lt;/code&gt; bit, as the Google font was now being included through &lt;code&gt;after_setup_theme&lt;/code&gt;. This wasn’t working for me previously, so I’m not sure what changed there.&lt;/p&gt;
&lt;p&gt;Now, my editor styles enqueue looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function theme_editor_styles() {
  add_editor_style( &apos;https://fonts.googleapis.com/css?family=Work+Sans:400,500,700&apos; );
  add_editor_style();
}
add_action( &apos;after_setup_theme&apos;, &apos;theme_editor_styles&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is only one last thing to make this work, probably the most important. You have to tell the block editor that you want to use the editor stylesheet in this way. Again, as someone who likes control, I am glad that this is not automatic.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function theme_setup() {
  add_theme_support( &apos;editor-styles&apos; );
}
add_action( &apos;after_setup_theme&apos;, &apos;theme_setup&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Beautiful! Simple! Elegant! Both the classic editor and the block editor are now appropriately styled by the same stylesheet. Now, the only question that remains is, why didn’t I set it up this way to begin with? (the answer is documentation)&lt;/p&gt;
</content:encoded></item><item><title>Migrate WordPress install from one DigitalOcean droplet to another</title><link>https://samhermes.com/posts/migrate-wordpress-install-from-one-digitalocean-droplet-to-another/</link><guid isPermaLink="true">https://samhermes.com/posts/migrate-wordpress-install-from-one-digitalocean-droplet-to-another/</guid><pubDate>Sat, 22 Feb 2020 19:49:00 GMT</pubDate><content:encoded>&lt;p&gt;Alternate title: “Upgrade” Ubuntu from 14.04 to 18.04 by just starting over with a fresh droplet because that’s far far easier than actually upgrading.&lt;/p&gt;
&lt;p&gt;Gather ‘round kids, story time. We begin with my old droplet. There, I was running &lt;a href=&quot;https://certbot.eff.org&quot;&gt;Certbot&lt;/a&gt; to enable HTTPS. It worked beautifully, was really easy to set up, handled renewals quietly, it was great… until a couple of weeks ago when I received an email about ACMEv2. Apparently the version of Certbot that I had installed was running ACMEv1. And, apparently, the ACME protocol, &lt;a href=&quot;https://letsencrypt.org/docs/client-options/&quot;&gt;according to the Let’s Encrypt&lt;/a&gt; website, is the bit that it uses to “verify that you control a given domain name and to issue you a certificate.” Sounds important.&lt;/p&gt;
&lt;p&gt;The problem, if you’re at all aware of Ubuntu versions, is that my old droplet was running a very, very out of date version. So out of date, in fact, that it reached its end of life &lt;a href=&quot;https://www.omgubuntu.co.uk/2019/04/ubuntu-14-04-end-of-life&quot;&gt;almost a year ago&lt;/a&gt;. So, when I went to upgrade Certbot, it was stuck. I don’t blame it. In the Certbot documentation, it doesn’t even talk about Ubuntu 14.04.&lt;/p&gt;
&lt;p&gt;As I started to investigate the possibility of upgrading Ubuntu, it became clear that this would be very messy and complicated, and way over my head. Sure, I could probably eventually get it figured out, but there’s actually a site running on the droplet that needed to remain available.&lt;/p&gt;
&lt;h2&gt;Starting over&lt;/h2&gt;
&lt;p&gt;So, plan of attack was to create a new droplet, move the WordPress install, and then point the domain to the new droplet. Easy enough? I first started by using the WordPress image from the Marketplace. Makes is super easy. It had Ubuntu 18.04 on it, and all the stuff that WordPress needs (plus, Certbot!).&lt;/p&gt;
&lt;p&gt;From there, I configured the WordPress install. This required accessing the site through an IP address, as I couldn’t use my domain yet. The old droplet was running a multisite install, so I made sure that the new instance was too.&lt;/p&gt;
&lt;h2&gt;The migration&lt;/h2&gt;
&lt;p&gt;I have long struggled with migrations. To migrate the WordPress content from one server (or droplet, in this case) to another, there are two parts: the database and the wp-content folder. The wp-content part is easy, and at bare minimum, it could be copied via FTP (lots of people just closed out of this article 😓). The database is usually a little more mysterious to me. This time, though, I found a great article that helped me a lot:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@devron/using-wp-cli-to-migrate-wordpress-to-another-server-or-your-dev-environment-bded1c78b9ee&quot;&gt;Using WP-CLI To Migrate WordPress to another server or your dev environment&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Skipping ahead to step 3, I did notice that the directory to the WordPress install was different between my two droplets. I wasn’t expecting them to be different, so something to watch for.&lt;/p&gt;
&lt;p&gt;In step 4, the database migration takes place. The article does a pretty good job of explaining this, and the commands it suggests worked great for me. The first command in which it exports the database includes a &lt;code&gt;&amp;gt;&lt;/code&gt;, which I wasn’t familiar with. Apparently it translates to “output to,” which is &lt;a href=&quot;https://en.wikipedia.org/wiki/Redirection_%28computing%29&quot;&gt;part of a broader set of redirection commands&lt;/a&gt;. The article actually gets into this at the bottom. Essentially, the database is exported to an SQL file, copied to the new server, and then imported.&lt;/p&gt;
&lt;p&gt;Next, I used &lt;code&gt;wp search-replace&lt;/code&gt; as the article suggests to replace the domain with the IP address that I’d been using to access the site. This wasn’t necessary, as I could’ve just pointed the domain and gone from there. But, I wanted to get into the site and verify that everything had copied over correctly. I used this again after I’d pointed the domain to switch back.&lt;/p&gt;
&lt;p&gt;Step 5 is where the migration of the wp-content folder takes place. The article suggests using &lt;code&gt;rsync&lt;/code&gt; for this, and that was a new one for me. I hadn’t used it between servers before. This worked magically. I feel ridiculous for not having this in my toolkit already. It copied all of the files directly from one server to the other. Using FTP, I would’ve copied this all down from the older server to my machine and then back up to the new server. Like a caveman.&lt;/p&gt;
&lt;h2&gt;Remaining issue&lt;/h2&gt;
&lt;p&gt;After I completed the migration, I noticed that there were some plugin updates. I normally just run these in the admin, but I kept getting an error message: “Update Failed: The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.” I eventually just updated these manually on the server. Comparing the folder and file permissions, I’m not sure what is wrong, as they match. If you have any ideas... let me know.&lt;/p&gt;
</content:encoded></item><item><title>Using RadioControl in a custom Gutenberg block</title><link>https://samhermes.com/posts/using-radiocontrol-in-a-custom-gutenberg-block/</link><guid isPermaLink="true">https://samhermes.com/posts/using-radiocontrol-in-a-custom-gutenberg-block/</guid><pubDate>Sat, 25 Jan 2020 21:52:00 GMT</pubDate><content:encoded>&lt;p&gt;Why was this so complicated? So much of developing with Gutenberg is simply finding all of the necessary bits of information to bring it all together. The official documentation is a little sparse on the &lt;a href=&quot;https://developer.wordpress.org/block-editor/components/radio-control/&quot;&gt;RadioControl&lt;/a&gt; front. It seems directed more towards the core developers. Which, is fine, but I think it’s really cool and want to use it too.&lt;/p&gt;
&lt;p&gt;The first question: how do we get this component added to our block? Here, the official documentation is helpful.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import { RadioControl } from &apos;@wordpress/components&apos;;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Next, we need to add an attribute to the block to store the value of the RadioControl. Here, the documentation wasn’t very clear. What type of attribute should it be? What other arguments might it need?&lt;/p&gt;
&lt;p&gt;Also, how is a default value set? The documentation stresses the need to have one. It is simply though the &lt;code&gt;default&lt;/code&gt; argument, and then the slug of the radio option.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;attributes: {
  radio: {
    type: &apos;string&apos;,
    default: &apos;option-one&apos;,
  },
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Very simple in hindsight, but hard to figure out when an example is hard to come by.&lt;/p&gt;
&lt;p&gt;Now, on to actually adding the &lt;code&gt;RadioControl&lt;/code&gt; to the block. Inside of the edit function, and inside of &lt;code&gt;InspectorControls&lt;/code&gt;, we add a &lt;code&gt;RadioControl&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;RadioControl
  label={__(&apos;Radio control&apos;, &apos;textdomain&apos;)}
  help=&quot;Description of radio control&quot;
  selected={ radio }
  options={ [
    { label: &apos;Option One&apos;, value: &apos;option-one&apos; },
    { label: &apos;Option Two&apos;, value: &apos;option-two&apos; },
  ] }
  onChange={ ( option ) =&amp;gt; { setAttributes( { radio: option } ) } }
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the component documentation, it uses &lt;code&gt;setState&lt;/code&gt; to store the updated option. Here, I’m using &lt;code&gt;setAttributes&lt;/code&gt;. In order to use &lt;code&gt;setAttributes&lt;/code&gt; like this, it needs to be defined. At the top of the edit function, we can bring it in with the &lt;code&gt;radio&lt;/code&gt; attribute we created.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;const { attributes: { radio }, setAttributes } = props;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The last piece here is using the &lt;code&gt;radio&lt;/code&gt; value in the block itself, both in the &lt;code&gt;edit&lt;/code&gt; and &lt;code&gt;save&lt;/code&gt; function. The attribute only stores the slug of the option selected, so we can check that value using a conditional statement.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ radio &amp;amp;&amp;amp; radio === &apos;option-one&apos; &amp;amp;&amp;amp; (
  // set class name, include element, etc. here
)}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Strangely, most of this came together for me from reviewing the &lt;a href=&quot;https://github.com/WordPress/gutenberg/tree/master/packages/block-editor/src/components/inspector-controls&quot;&gt;InspectorControls component on GitHub&lt;/a&gt;. So, if you’re still missing a piece of this puzzle, or need a look at the bigger picture, that might be a good place to look.&lt;/p&gt;
</content:encoded></item><item><title>Using Docker for local WordPress development</title><link>https://samhermes.com/posts/using-docker-for-local-wordpress-development/</link><guid isPermaLink="true">https://samhermes.com/posts/using-docker-for-local-wordpress-development/</guid><pubDate>Sun, 19 Jan 2020 23:32:00 GMT</pubDate><content:encoded>&lt;p&gt;I definitely knew about Docker before this, but I’d never really started from the beginning. Fair warning, most of this is going to essentially be a stream of consciousness as I attempt to set up Docker for local WordPress development. There are better guides out there, but I wanted to capture some of the questions or uncertainty that I had throughout, possibly that others haven’t answered or addressed previously. You know, noob stuff.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;If you’d like to skip to the part where I’ve got it all figured out,&lt;/strong&gt;&lt;/em&gt; &lt;a href=&quot;#putting-it-all-together&quot;&gt;&lt;em&gt;&lt;strong&gt;come with me to the bottom of this article&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Docker Desktop app&lt;/h2&gt;
&lt;p&gt;I started by downloading the Docker app from their website. I like a GUI, so it seemed like a good place to start. It installed, I opened it, and now it says that “Docker Desktop is running” in the menu bar dropdown. Okay, cool, so the app that I opened is running... Like with most new software, it’s hard to know what it all means. Usually when an app is running, it’s running. So.&lt;/p&gt;
&lt;p&gt;Apparently, Docker Desktop installs Docker “Engine” on your machine as part of the installation process, which is basically the main bit of software that makes Docker work. &lt;a href=&quot;https://docs.docker.com/docker-for-mac/install/&quot;&gt;According to their documentation site&lt;/a&gt;, you also get Docker CLI client, Docker Compose, Docker Machine, and Kitematic as part of the installation. So, we have a lot of stuff. Cool.&lt;/p&gt;
&lt;h2&gt;Docker Hub&lt;/h2&gt;
&lt;p&gt;During the installation process, it has you go through some steps to create a Docker account, create a sample repository, and pull it down to your machine. It’s supposed to teach you how it works, I assume, but it mostly just made me more confused.&lt;/p&gt;
&lt;p&gt;First, didn’t know that Docker had repositories. With a Docker Hub account, you can store your “containers” in repositories. I was thrown off by the use of the word “repository” in this context. Is a repository just a container? To confuse this further, if you go to the Explore page in Docker Hub, it lists containers that you can use. Each of these is an “image.” Listen, I went to college. I’m not dumb. I’ve been using computers for a long, long time. Why is each new thing so confusing?&lt;/p&gt;
&lt;p&gt;For now, let’s move on.&lt;/p&gt;
&lt;h2&gt;Installing WordPress&lt;/h2&gt;
&lt;p&gt;While exploring the available images in Docker Hub, I found one for WordPress. It’s near the top of the popular list, which makes sense. I clicked through to it, and just had a lot of questions really quickly. The main action, it appears, is to pull the image. It suggests &lt;code&gt;docker pull wordpress&lt;/code&gt; at the top of the page. Further down, there’s a section called “How to use this image” and instructions to run &lt;code&gt;docker run --name some-wordpress --network some-network -d wordpress&lt;/code&gt;. So, wait, which one do I want? I can pull the image down, or seemingly just run it? Do I pull it down first, or just run it?&lt;/p&gt;
&lt;p&gt;So, from here, I just Googled “local wordpress development docker” and read through the first few results. On &lt;a href=&quot;https://themeisle.com/blog/local-wordpress-development-using-docker/&quot;&gt;this ThemeIsle article&lt;/a&gt; from 2018, I was with it until it wanted me to create a configuration file. So, step 2. So, now I’m more confused. Do I need to do a manual configuration, or can I just use the WordPress image from Docker? Why isn’t this article just starting me out with the very basics?&lt;/p&gt;
&lt;p&gt;Okay, I have &lt;strong&gt;got&lt;/strong&gt; to start answering some of these questions.&lt;/p&gt;
&lt;p&gt;I started at the top. I ran &lt;code&gt;docker pull wordpress&lt;/code&gt; in my terminal and watched as it downloaded the image. It took like 10 seconds or so and then it was done. That was it. So, now I have it on my machine. Where? Do not know. How do I use it? Do not know.&lt;/p&gt;
&lt;p&gt;Next, I created a new directory in my user directory called “Docker” and inside of it, I created another directory called “wp,” just for testing purposes. In my terminal, I &lt;code&gt;cd&lt;/code&gt;’d to that directory and went to the next command, &lt;code&gt;docker run --name some-wordpress --network some-network -d wordpress&lt;/code&gt;. First, name seems pretty easy. I changed it from &lt;code&gt;some-wordpress&lt;/code&gt; to &lt;code&gt;wp&lt;/code&gt; to match my directory. Network, though, was a little puzzling. Can it be anything? No, of course not!&lt;/p&gt;
&lt;p&gt;I ran the command just the way it was to see what would happen. &lt;code&gt;docker: Error response from daemon: network some-network not found.&lt;/code&gt; was the response. Well, figures. Didn’t expect it would find it. Back to the image page. There, a little bit further under the “How to use this image” section, it suggests that “standard port mappings can be used,” and then repeats the command with them in place: &lt;code&gt;docker run --name some-wordpress -p 8080:80 -d wordpress&lt;/code&gt;. I modified my initial command to use &lt;code&gt;-p 8080:80&lt;/code&gt; instead. It did something very quick and then gave me a really long hash! Great… what does it mean?&lt;/p&gt;
&lt;p&gt;From the docs, I learned that I could run &lt;code&gt;docker ps&lt;/code&gt; for a list of the currently running containers. I ran that, and could see that the container I created was there. So, I opened my browser, and visited &lt;code&gt;localhost:80&lt;/code&gt;. Nothing found. Isn’t that where it would be? Back to the WordPress image page, it states that the site is available at &lt;code&gt;http://localhost:8080&lt;/code&gt;. Ah, right. So, I opened that up, and it’s the WordPress startup page! Woohoo!&lt;/p&gt;
&lt;p&gt;The excitement was short-lived, though. On the database connection page, I was again lost. What’s the name of the database? What’s the username/password? Is there a database? Of course there is, right? That super quick command I ran that took about 1 second to give me a random hash surely spun up a database! Right…?&lt;/p&gt;
&lt;p&gt;Maybe &lt;code&gt;root&lt;/code&gt; is the username? But what is the database name? It was pre-filled with “wordpress” but that didn’t seem likely.&lt;/p&gt;
&lt;h2&gt;Maybe this isn’t for me&lt;/h2&gt;
&lt;p&gt;At this point, I’m close to giving up. This is a sysadmin tool and I’m not a sysadmin. Back at Google, I just search for “docker” and read “Learn how Docker helps developers bring their ideas to life by conquering the complexity of app development” under the result for the official Docker site. Oh no, I haven’t conquered anything.&lt;/p&gt;
&lt;p&gt;I’ve been using VVV for my local WordPress development for over four years now, maybe five? My assumption was that Docker would be better than Vagrant, or easier to understand.&lt;/p&gt;
&lt;h2&gt;Finally, breakthrough&lt;/h2&gt;
&lt;p&gt;I returned to my “local development wordpress docker” search and came across &lt;a href=&quot;https://neliosoftware.com/blog/local-wordpress-development-with-docker/&quot;&gt;this article&lt;/a&gt;. In it, in speaking about the WordPress image I had used, it states, “this image doesn’t include the database system.” Ah, I see. So it’s a WordPress container, with &lt;em&gt;just&lt;/em&gt; WordPress in it. Now I know why I was at a loss for the database credentials. It didn’t even exist.&lt;/p&gt;
&lt;p&gt;As part of further Googling, I came across &lt;a href=&quot;https://github.com/10up/wp-local-docker-v2&quot;&gt;10up’s WP Local Docker&lt;/a&gt;. Okay, now we’re really getting somewhere. This is what I assumed the Docker Hub image was. In fact, the reason most of the articles suggest starting with a configuration file is that it’s necessary to bring the database and WordPress together. Fortunately, WP Local Docker takes care of this piece.&lt;/p&gt;
&lt;p&gt;By the way, the &lt;a href=&quot;https://10up.github.io/wp-local-docker-docs/&quot;&gt;documentation on 10up’s site for WP Local Docker&lt;/a&gt; is great, except every time I land on one of their documentation sites, I assume that the top navigation is global for 10up itself, so I have a bit of a blind spot. In this case, the navigation is for WP Local Docker specifically. The 10up logo will take you to the WP Local Docker homepage, not the 10up site itself. I… have some feedback.&lt;/p&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;First, install &lt;a href=&quot;https://www.docker.com/products/docker-desktop&quot;&gt;Docker Desktop&lt;/a&gt; on your machine. This will get all of the necessary components installed, like the Docker Engine, Docker CLI, and Docker Compose.&lt;/p&gt;
&lt;p&gt;Next, globally install the NPM package for WP Local Docker from 10up using &lt;code&gt;npm install -g wp-local-docker&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To create your first site, run &lt;code&gt;10updocker create&lt;/code&gt;. It will prompt you with questions.&lt;/p&gt;
&lt;p&gt;The first time I ran this, I received an error message: &lt;code&gt;ERROR: for mysql  Cannot start service mysql: b&apos;Mounts denied: The path /usr/local/lib/node_modules/wp-local-docker/global/config/mysql/config.cnf is not shared from OS X and is not known to Docker.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To remedy this, I added &lt;code&gt;/usr/local/lib/node_modules/wp-local-docker/global/config/mysql&lt;/code&gt; to the File Sharing preferences in Docker Desktop. It worked. I assume that this is a bug with WP Local Docker, and may be fixed? I’m not sure why just mysql had trouble and not the others.&lt;/p&gt;
&lt;p&gt;Now, the new site is up and running at the address you specified during setup. Run &lt;code&gt;docker ps&lt;/code&gt; and you’ll see all of the containers involved in bringing the site together. Quite a few more than I was trying to start with.&lt;/p&gt;
&lt;h2&gt;Finishing up&lt;/h2&gt;
&lt;p&gt;Going back to the articles that I started with, it’s easy to see how starting with a configuration file makes the most sense. You can say exactly what you want. However, this often seems to leave out the networking part. Using custom domains like &lt;code&gt;wordpress.test&lt;/code&gt; is hard to do when you’re starting out with a custom configuration. It seems like using WP Local Docker at least solves this issue more quickly than someone could on their own.&lt;/p&gt;
&lt;p&gt;This was really similar to how I started with VVV. I didn’t know what Vagrant or VirtualBox were, and even VVV was kind of complicated to get the hang of. I used a tool called Variable VVV (gosh, what a confusing name) that walked through questions similar to WP Local Docker, just to simplify the process. It was good, as it got me going quickly, but I was unfamiliar with what it had actually done.&lt;/p&gt;
&lt;p&gt;Now, I’d like to more deeply understand how to set up my own Docker configuration file. It seems like I can find good examples of the database and WordPress pieces, but getting it all set up to work with custom domains is a little more involved. Something to keep plugging away at!&lt;/p&gt;
&lt;h2&gt;Goodbye VVV?&lt;/h2&gt;
&lt;p&gt;Eh… I don’t think so. I think it works just fine for now. So yeah, maybe this was all just a learning exercise. 😭&lt;/p&gt;
</content:encoded></item><item><title>What does it mean to be a creator on the web?</title><link>https://samhermes.com/posts/what-does-it-mean-to-be-a-creator-on-the-web/</link><guid isPermaLink="true">https://samhermes.com/posts/what-does-it-mean-to-be-a-creator-on-the-web/</guid><pubDate>Mon, 30 Dec 2019 18:38:00 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;a href=&quot;https://contractfortheweb.org&quot;&gt;Contract for the Web&lt;/a&gt; that Tim Berners-Lee put forth last month has been bouncing around the web. &lt;a href=&quot;https://contractfortheweb.org/principles/principle-7-be-creators-and-collaborators-on-the-web/&quot;&gt;Principle 7&lt;/a&gt; of the contract states that citizens should “Be creators and collaborators on the Web.” It was the only principle that jumped out at me, I think because “creator” is just one of those words right now. What does it mean? It’s been heavily diluted, applied to just about everybody. Post photos on the web? You’re a creator! It pairs nicely with “content,” an equally nebulous term at this point.&lt;/p&gt;
&lt;p&gt;Without digging in and actually reading what Principle 7 meant, I assumed that “creator” here was the current popular idea of a creator. That, the principle was suggesting that individuals should be putting stuff on the internet, whatever that may be. Uploading photos and sharing thoughts and leaving comments or whatever else it is that people are compelled to do. But that’s not really what is meant. “Creator” here is used to refer to people adding… things of value? Unfortunately, that’s just as hard to stick a tack in.&lt;/p&gt;
&lt;p&gt;Looking at the &lt;a href=&quot;https://contractfortheweb.org/principles/principle-7-be-creators-and-collaborators-on-the-web/&quot;&gt;definition of Principle 7&lt;/a&gt;, it says that we should “share information of public interest.” Sounds quite noble, and also sounds like much of what currently gets added to the popular web does not count. It seems the word “information” is the key element here. Information helps people. It makes them more informed [rimshot]. It allows them to accomplish something or improve their world view. Social media takes up most of the airwaves, but there’s a quieter web underneath full of rich information. The good bits of social media use this part of the web, but it’s getting more and more difficult to merge the two as the walled gardens get taller and taller.&lt;/p&gt;
&lt;p&gt;“Public interest” seems a little more nebulous to me, but just as important. On &lt;a href=&quot;https://en.wikipedia.org/wiki/Public_interest&quot;&gt;Wikipedia&lt;/a&gt;, it’s defined as “the welfare or &lt;a href=&quot;https://en.wikipedia.org/wiki/Well-being&quot;&gt;well-being&lt;/a&gt; of the general public.” When a definition includes a link to another definition, you know you’re already headed down the rabbit hole. But, generally, Principle 7 seems to be out to help people. It’s difficult to put parameters around this, but &lt;a href=&quot;https://hls.harvard.edu/dept/opia/what-is-public-interest-law/public-interest-issue-areas/&quot;&gt;this list from Harvard Law&lt;/a&gt; seems to do a pretty good job. This is from a law perspective, though, so I don’t think it would be complete. Interesting to mull some of these over though, in how they would translate to the web.&lt;/p&gt;
&lt;p&gt;Most government websites, at least here in the US, are not good. Even if they are designed well, it’s hard to get all of the information that you need from them. When I’m trying to figure something out, I often have many, many tabs open. For government, it’s tricky because each person is going to have different circumstances. Doing work on these sites can have a huge impact though. Watching the healthcare.gov rollout in 2013 (yikes, that was a while ago!) was stressful. That was the web letting a lot of people down, in a way that was absolutely public interest. We’ve collectively learned a lot since then, but it still serves as a poignant example of how important the open web can be for all people.&lt;/p&gt;
</content:encoded></item><item><title>From developer to manager</title><link>https://samhermes.com/posts/from-developer-to-manager/</link><guid isPermaLink="true">https://samhermes.com/posts/from-developer-to-manager/</guid><pubDate>Wed, 18 Dec 2019 16:39:00 GMT</pubDate><content:encoded>&lt;p&gt;About six months ago, I made the move from developer to developer/manager. It wasn’t the typical clean break, as the role is still actively involved in doing some development work. I’m on a smaller team, so this arrangement works well and makes sense. Plus, for me, I’m only about five and a half years into my career, so hanging up my developer hat completely seemed crazy. Anyway, the important part is that I have new responsibilities!&lt;/p&gt;
&lt;p&gt;I wanted to reflect on this change a little, and now seems like as good a time as any to do so. It&apos;s been long enough that I&apos;m in the new role, but not so long that the transition is totally complete. As with all things in adulthood, it takes time, and that’s exactly how it should be.&lt;/p&gt;
&lt;h2&gt;First, the good&lt;/h2&gt;
&lt;h3&gt;I wanted this&lt;/h3&gt;
&lt;p&gt;Deep down, I wanted to be a manager. Now I am. Woo! Some of the work I was doing in my developer role was already some of the stuff of management. Strategic thinking, team organization, standards development. These were things that I was doing not just for myself. Now that I’m more empowered in my new role, I can take what I’ve done and actually put it in play. With that, I can get more direct feedback, I can make adjustments, and learn as I go. So far, this has been highly rewarding.&lt;/p&gt;
&lt;h3&gt;Environment is everything&lt;/h3&gt;
&lt;p&gt;I have a super supportive team. The people around me know about the transition, are here to help, and understand that things aren’t going to be magical overnight. I love them for that. Plus, the fact that I knew the people I would be managing made it that much easier. I know how they work, I trust them, the foundation is there. I think coming into this role from the outside would have been a huge undertaking. The opportunity to take this on while already being in the environment is a huge advantage.&lt;/p&gt;
&lt;h3&gt;Starting 1:1s&lt;/h3&gt;
&lt;p&gt;Shortly after taking on my new role, I started weekly, half-hour long 1:1s with each of my team members. This has been incredibly helpful so far, and is the one constant that (I think) has held this whole thing together over time. Each week, I know that I’ve dedicated at least that much time and attention with the team.&lt;/p&gt;
&lt;p&gt;At first, I worried that weekly would be too often. That we would run out of things to talk about. That they would seem tedious or overbearing. And they might be, at least occasionally. It has taken a little while to get into a groove, but it’s getting there.&lt;/p&gt;
&lt;p&gt;In the 1:1s, rather than getting into the nitty gritty, I try to get a feeling. Has it been overwhelming, underwhelming, stressful, relaxing? If the week before was taxing, has this week been restorative? Is there something looming that we can pick apart a little, break down into less stressful pieces? It’s interesting to try starting these in the way that makes the most sense to me, and then following it wherever it may go.&lt;/p&gt;
&lt;h2&gt;Now, the hard stuff&lt;/h2&gt;
&lt;h3&gt;Answering questions&lt;/h3&gt;
&lt;p&gt;I need to know the stack. This was a big shift. I&apos;d been specializing in specific projects or features, but now I need the full knowledge base. Context, previous decisions, system-wide effects, etc. It’s expected that I am up to speed and ready to help or advise with almost anything. So, each day I am challenged to go deep, research, and connect the dots. Each day I get better and more informed in ways that I didn’t need to before. It’s hard to be a fish out of water so often, but it’s growth and opportunity (or, on a bad day, it’s exhausting and overwhelming 😅).&lt;/p&gt;
&lt;h3&gt;Handing off work&lt;/h3&gt;
&lt;p&gt;Because I am still dedicating time to development, it’s hard to know what I should take on myself and what I should hand off. I was busy before, and therefore I’m the most knowledgeable person about quite a few things, just because of sitting with it the longest. I have the backstory, so handing off is hard work, not just in convincing myself that I should do it but actually gathering up all the knowledge that I have to hand off too. This has to happen though, and it will, over time.&lt;/p&gt;
&lt;h3&gt;Shifting relationships&lt;/h3&gt;
&lt;p&gt;Previously, I was working alongside the developers that are now reporting to me. That&apos;s a strange transition for everyone! Fortunately, we knew each other. Plus, shifting my mindset has been gradual for me, so the way I approach situations has been slowly morphing. I am more often put into my managerial role by someone else than I put myself into it.&lt;/p&gt;
&lt;p&gt;Despite all of this, I know that to others, the change in role was more abrupt. Communicating that I am still the same person with the same priorities has been a low-key goal of mine. I don’t want to find myself (or others to find me) disconnected from the work because of this change, so maintaining my position as an engaged team player is important. I want to know what’s going on, what’s going well or poorly, and help as much as possible.&lt;/p&gt;
&lt;h3&gt;Setting priorities&lt;/h3&gt;
&lt;p&gt;With great power comes great responsibility. I now feel a new pressure to prioritize absolutely everything. My time is more limited now, so I need to be focused every day. And that focus has to be flexible. Yikes! Not only that, but I need to set priority for the team. Setting my own priorities has felt fairly natural, and I created a document that I refer to regularly with just an ordered list of the high-level projects and initiatives I want to keep an eye on. Overall, this was the least difficult transition to make.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In another six months, I’m sure I can return here and say more about what this change has meant. There are still challenges coming, and more that will need reflection. It’s been really exciting to have an opportunity to try out something that I had been curious about. I have already been able to grow so much in my personal and professional life because of this, and I can’t wait for the future.&lt;/p&gt;
</content:encoded></item><item><title>Internet + Dignity</title><link>https://samhermes.com/posts/internet-plus-dignity/</link><guid isPermaLink="true">https://samhermes.com/posts/internet-plus-dignity/</guid><pubDate>Mon, 11 Nov 2019 01:18:00 GMT</pubDate><content:encoded>&lt;p&gt;I came across this article recently that speaks about dignity and the internet. I thought that it was an interesting take on the issue, and shows how complex this is.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://time.com/5505431/internet-feel-awful-dignity/&quot;&gt;The Internet Can Make Us Feel Awful. It Doesn&apos;t Have to Be That Way (time.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One issue that I have with the article is the use of “the internet” to really mean “popular social media.” When we look outside of these gamified environments, the internet is a safe and helpful place. You can read information, make purchases, register for classes. There is a lot of utility outside of popular internet that is aware of your dignity and status as a real life human being.&lt;/p&gt;
&lt;p&gt;Similar to fast food, just because a lot of people eat there, it doesn’t mean that it is a good thing.&lt;/p&gt;
</content:encoded></item><item><title>Software is like a city</title><link>https://samhermes.com/posts/software-is-like-a-city/</link><guid isPermaLink="true">https://samhermes.com/posts/software-is-like-a-city/</guid><pubDate>Mon, 28 Oct 2019 16:56:00 GMT</pubDate><content:encoded>&lt;p&gt;Before I deep dive into this, a quick disclaimer to say that this is merely a thought exercise. Enjoy!&lt;/p&gt;
&lt;p&gt;I live in a city and I write software for a living, and so I spend quite a bit of time thinking about both. I think that there is a lot of overlap between the two, just looking at them at a high level as complex systems. I am frequently frustrated by the city, as just as much by software.&lt;/p&gt;
&lt;p&gt;The promise of a city is the potential. Come here, and through our shared resources, we’ll make something amazing happen. Software is much the same. We can make things with software, and there is a lot of potential.&lt;/p&gt;
&lt;p&gt;Potential is great, but it isn’t the part that we often experience in the day-to-day. Of course, being in a city affords opportunities, much like writing software, but the bottlenecks often create more friction that you might want to imagine. The travel brochures and conference talks rarely speak of issues that are very difficult to fix. The backlog of bugs is more omnipresent than the future roadmap.&lt;/p&gt;
&lt;p&gt;For example, the internet infrastructure is much like a city highway. At a certain point, there’s too much traffic and everything grinds to a slow crawl. With software, the server topples over or stops responding. Your connection slows down when too many people are streaming Netflix. There is great potential, but once the limit is hit, it’s a bummer. From your streaming TV or behind the wheel, there’s not much you can do about it.&lt;/p&gt;
&lt;p&gt;When there’s a bug in software, we assign someone to fix it. It might take a while to fix, or it needs to go through a process before being deployed, but there’s usually something we can do about it. Same with a pothole. However, sometimes that bug is non-critical. It could even be something that never warrants a fix. Same with a pothole. If a street has no traffic, why fix a pothole? Yes, we want to take care of things, but there are usually other bugs and more important roads to address.&lt;/p&gt;
&lt;p&gt;In software, the focus usually rests on bringing on new features and functionality. Much like opening a new street, it’s very difficult to walk this back. If we find that we don’t have the resources to support the new, it can sometimes be a tangle to unwind it all. Maybe the new street leads to a newly constructed business. Maybe the new search feature raises the bar for what’s possible. In each of these, we’ve introduced a new reality, and cancelling is a bummer! No one wants to pull the plug. Potential above all!&lt;/p&gt;
&lt;p&gt;Speaking of bugs and features, the process of how both are introduced is one fraught with instability. Accidentally introducing a bug could have huge consequences, especially if it’s in something like a payment system. In this case, a single person could have an outsize impact on the entire system. Granted, they likely didn’t mean to, but they have that power. Again, to keep going with this metaphor, a single person could get into an accident on a highway, and cause all of the traffic to be rerouted for hours. It’s a huge disruption that makes people late, annoyed, and inconvenienced. All because of a single person. It’s a strange unbalance.&lt;/p&gt;
&lt;p&gt;A city at large has a status. The residents have a feeling for how things are going. Can they get where they need to go? Are there businesses that provide the goods they need to live? Can they expect to be safe? Naturally, cities are far more important in this case, but software also has this status. In fact, it’s here where the two come closest. Does the software work? Do I have confidence in the software? As cities place more dependence on software to serve their residents, can they keep up? At the DMV, when software fails, residents are rightfully irate. Not only is software in a bad state, so is the city.&lt;/p&gt;
&lt;p&gt;As we depend on our cities to take care of us, so too do we depend on software to always be in good working order. Getting back to potential, we can begin to see where this all falls apart. Yes, a city can expand and grow in size and density. So too can we add more lines of code. With each addition, we increase our overall support burden. With unlimited potential also comes compounding maintenance costs. When things are going so well that we continue to add, we rarely stop to think about a year or two down the line.&lt;/p&gt;
&lt;p&gt;The longer that I work in software development, the greater the appreciation I have for how cities are managed. Yes, the road that I frequently drive on is in bad shape, but it’s competing for resources against every single other road in the city. It’s less travelled than most of them. Yes, my website has a bug, but unfortunately the greater system has bigger issues that need to be addressed first. In building and maintaining a system, prioritization is paramount. Without a way to address the most pressing issues first, we don’t know how to help the most people.&lt;/p&gt;
&lt;p&gt;Fortunately, most of us do not have to manage software being used by millions of people at a time. Thinking about the teams behind iOS, my eye twitches for them. Their software is super successful! And buggy! There are horrible bugs that none of us even know about. Their success makes each of their bugs just that much more critical. This brings us to the MTA, naturally. A huge, complex system that is hugely successful by proxy of NYC’s success, that is riddled with problems. Deep, deep, problems that are only exacerbated by how many people rely on it. A small improvement has a huge impact. A medium sized problem is catastrophic. It’s almost better to be an unpopular city. It’s almost better to have an app that only a small group of people use.&lt;/p&gt;
&lt;p&gt;I think that I use this comparison in my mind so frequently as a way to lessen the stress of software. As technology is so shiny and new, it gives the idea that the software we write should also be. But like any complex system, there is a balance. Perfection does not exist, much like the perfect city is only in imagination. It just means that there is work to be done, and every day we get the chance to make things a little better.&lt;/p&gt;
</content:encoded></item><item><title>Revisiting my WordPress work from 2013</title><link>https://samhermes.com/posts/revisiting-my-wordpress-work-from-2013/</link><guid isPermaLink="true">https://samhermes.com/posts/revisiting-my-wordpress-work-from-2013/</guid><pubDate>Tue, 10 Sep 2019 21:40:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s pretty rare that you get to return to a project after six years, but that’s just what I’ve been up to! Even though I’d love to never tell anyone about the mistakes that I made, why not make them useful.&lt;/p&gt;
&lt;p&gt;Naturally, I’ve gotten much much better at my job since, but these were mistakes that I made when I was still very new. And there are new new people all the time! If you’re just starting out with WordPress development, these should be helpful. Or, if you’re an experienced WordPress professional, you can enjoy being incredibly uncomfortable. Get ready to cringe.&lt;/p&gt;
&lt;h2&gt;Child themes should be child themes, or just their own theme&lt;/h2&gt;
&lt;p&gt;Mistake #1: I modified the parent theme at the same time that I was adding to the child theme. Starting out, if there was something that I wasn’t sure how to modify in the child theme, I just edited the parent theme. In this case, that theme was Twenty Twelve. You’re in actual pain, right?&lt;/p&gt;
&lt;p&gt;Now, returning to this project after so much time has passed, I have no idea what it was that I changed in Twenty Twelve. What is specific to this project, and what is just part of Twenty Twelve? Hard to know at first glance.&lt;/p&gt;
&lt;p&gt;So, what to do? First, I cloned the WordPress repository to my local machine (which takes a minute), and then I copy/pasted the modified version of Twenty Twelve over it. Now, Twenty Twelve has had some fixes and miscellaneous changes since 2012, so this isn’t a clean comparison. Security fixes and the like have been committed since then, but this helps piece apart what changes I made.&lt;/p&gt;
&lt;p&gt;With this, I could see the functions and styles that I added or modified and copy them over to the new theme. It wasn’t a hopeless situation, and this is exactly why version control is super helpful to have in the toolkit.&lt;/p&gt;
&lt;p&gt;Fun fact, Twenty Twelve has block styles for Gutenberg support! That’s a special kind of backwards compatibility.&lt;/p&gt;
&lt;h2&gt;How to tell what styles are being used?&lt;/h2&gt;
&lt;p&gt;So, when you’re making a child theme, you have the parent theme stylesheet and the child theme stylesheet running together.  In my case, most of those parent styles weren’t being used. Again, this project should have just used a parent theme, as it was very custom. It would be nice to just remove the parent theme styles, but they were serving as the base upon which the child styles were built upon. Removing them broke the layout, among other things.&lt;/p&gt;
&lt;p&gt;It would be nice to automate this in a way. See if we can determine which styles aren’t ever being used. Just include all of them and let the computer decide.&lt;/p&gt;
&lt;h2&gt;Includes!&lt;/h2&gt;
&lt;p&gt;Don’t repeat yourself. I did this work before I truly understood how to make that happen. This theme was chock full of code that I copied to a couple dozen files. Not a huge performance win for users, but super critical to sort out for future maintenance.&lt;/p&gt;
&lt;h2&gt;Rename functions that you copy from the internet&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;my_cpt&lt;/code&gt; is probably not a good function name that could conflict with a poorly written plugin or theme. Taking these straight from the internet or a plugin’s output (looking at you, Custom Post Type UI) can lead to trouble down the line. Much better to use &lt;code&gt;themename_add_post_types&lt;/code&gt; or something to that effect.&lt;/p&gt;
&lt;h2&gt;Client billing&lt;/h2&gt;
&lt;p&gt;Let’s talk about billing for a moment! Ooo, touchy subject. I did a lot of work on this project that the client did not ask for and will probably never feel. How do we bill? Well, I’m not. You could come at this in a couple of different ways.&lt;/p&gt;
&lt;p&gt;Had a different person been the developer on this project initially, and I was cleaning up their work, I’d bill for that. Even then, though, there’s some gray area. There’s a certain amount of cleanup that is necessary to get the job done. A dysfunctional project will make it really difficult to ship code that you’re confident will work.&lt;/p&gt;
&lt;p&gt;In this case, I was the previous developer, so I was cleaning up my own mess. I just took it as a chance to observe how much I had grown in the time since I worked on the project. In addition, there’s a certain satisfaction from making things orderly and applying best practices, laying the groundwork for the future.&lt;/p&gt;
</content:encoded></item><item><title>Implementing media controls in custom blocks</title><link>https://samhermes.com/posts/implementing-media-controls-in-custom-blocks/</link><guid isPermaLink="true">https://samhermes.com/posts/implementing-media-controls-in-custom-blocks/</guid><pubDate>Fri, 06 Sep 2019 22:51:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been deep in block development for the past few months, and through that, I’ve had to learn a lot of stuff! It’s been really fun, and at times a little challenging. One of the most confusing parts has been media controls. There doesn’t seem to be a plug-and-play implementation that Gutenberg gives you, which is great for flexibility and not so great for times that you just want to get going.&lt;/p&gt;
&lt;p&gt;So, what do we want to be able to do?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Upload images from our device or choose from the media library&lt;/li&gt;
&lt;li&gt;Have the chosen image display in our block the way that it would on the front end&lt;/li&gt;
&lt;li&gt;Allow the image to be updated later&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Fair warning, this is going to be a fairly slow explanation of what’s going on. If you’d like to see all of this together at once, head over to the Gutenberg Github and &lt;a href=&quot;https://github.com/WordPress/gutenberg/blob/master/packages/block-library/src/media-text/edit.js&quot;&gt;view the Media &amp;amp; Text edit function&lt;/a&gt;. I pulled a great bit from there.&lt;/p&gt;
&lt;h2&gt;The two media components&lt;/h2&gt;
&lt;p&gt;Gutenberg comes with two media components, &lt;code&gt;mediaUpload&lt;/code&gt; and &lt;code&gt;mediaPlaceholder&lt;/code&gt;. &lt;code&gt;mediaPlaceholder&lt;/code&gt; makes use of &lt;code&gt;mediaUpload&lt;/code&gt;, but gives us a little UI on top. For most blocks that need a standard media upload control, &lt;code&gt;mediaPlaceholder&lt;/code&gt; is a great place to start. To add both of them to your block:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { MediaPlaceholder, MediaUpload } = wp.editor;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, only add the one you need, if that’s the case. However, we’re going to take advantage of both, in different ways. Here we go!&lt;/p&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;p&gt;This is where things are a bit of a free-for-all, and you can really accomplish about anything that you’d like to. You could put all of the controls right in the block itself, in the block’s toolbar, or in the inspector controls in the sidebar. You could go absolutely mad!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Following WordPress&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You needn’t look far to get an impression of how the core developers think that this should work. It’s never explicitly said anywhere, but looking at the Media &amp;amp; Text block, you can see that the initial image upload is handled within the block itself, and then updates to the image can be made through a button in the toolbar.&lt;/p&gt;
&lt;p&gt;I believe in following WordPress, so that’s where I&apos;m going to take this. First, we need to add a couple of attributes to our block for the image URL.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;attributes: {
  mediaUrl: {
    type: &apos;string&apos;,
  }
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can add a &lt;code&gt;mediaPlaceholder&lt;/code&gt; to prompt the user to choose an image. Within the edit function of the block, right inside the block’s JSX, we add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{% raw %}&amp;lt;MediaPlaceholder
  icon=&quot;format-image&quot;
  labels={{
    title: __(&apos;Media area&apos;),
  }}
  className=&quot;block-image&quot;
  onSelect={onSelectMedia}
  accept=&quot;image/*&quot;
  allowedTypes={[&apos;image&apos;]}
/&amp;gt;{% endraw %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gets you pretty far, but this really needs to be nested inside of a conditional that will handle displaying the image on the page after you’ve uploaded or chosen it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image conditional&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this implementation, the conditional can be fairly simple. We check the attribute that we’re storing the image URL in, and if it has a URL, we render the image, and if not, we display the media placeholder.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{% raw %}{mediaUrl ?
  &amp;lt;div className=&quot;block-image&quot; style={{
      backgroundImage: `url(${mediaUrl})`
  }}&amp;gt;&amp;lt;/div&amp;gt;
  :
  &amp;lt;MediaPlaceholder
    icon=&quot;format-image&quot;
    labels={{
      title: __(&apos;Media area&apos;),
    }}
    className=&quot;block-image&quot;
    onSelect={onSelectMedia}
    accept=&quot;image/*&quot;
    allowedTypes={[&apos;image&apos;]}
  /&amp;gt;
}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see here that we’re sharing a class name between both the image markup and the media placeholder. This allows the styles to be shared between both. Depending on your block, this may not be what you’re needing. You could split this into two classes and style accordingly.&lt;/p&gt;
&lt;p&gt;The major functional piece of the MediaPlaceholder element is the &lt;code&gt;onSelect&lt;/code&gt; property. It accepts a callback function that handles the image upload process and stores the resulting image attributes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting up the callback function&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is the part of the media control that really complicated things for me. It’s incredibly flexible, but leaves a lot to the developer. Maybe too much. &lt;code&gt;mediaUpload&lt;/code&gt; and &lt;code&gt;mediaPlaceholder&lt;/code&gt; are just components, and they do not carry much functionality with them. The callback function needs to pull out the appropriate media attributes after a user makes a selection.&lt;/p&gt;
&lt;p&gt;Looking at the Media &amp;amp; Text block in Gutenberg, the &lt;code&gt;onSelectMedia&lt;/code&gt; seems fairly straightforward, apart from the &lt;code&gt;get&lt;/code&gt; function that is used to pick apart the media attributes in order to retrieve the URL of a specific image size. My inclination here was to reproduce this without depending on Lodash, but I wasn’t able to make it happen. This is something I want to work on in the future.&lt;/p&gt;
&lt;p&gt;In order to take advantage of &lt;code&gt;get&lt;/code&gt;, lodash needs to be added to the project dependencies. In the console:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install lodash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After it’s been added, we can then bring in just the &lt;code&gt;get&lt;/code&gt; function to our block:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { get } from &apos;lodash&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, on to the &lt;code&gt;onSelect&lt;/code&gt; function. We bring in &lt;code&gt;setAttributes&lt;/code&gt; from the block’s props. Next, it retrieves the large image size URL, falls back to the full size URL if needed, and then stores the URL in state. This function is a simplification of what is used in the Media &amp;amp; Text block in Gutenberg.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;onSelectMedia( media ) {
  const { setAttributes } = this.props;

  // Try the &quot;large&quot; size URL, falling back to the &quot;full&quot; size URL below.
  let src = get( media, [ &apos;sizes&apos;, &apos;large&apos;, &apos;url&apos; ] ) || get( media, [ &apos;media_details&apos;, &apos;sizes&apos;, &apos;large&apos;, &apos;source_url&apos; ] );

  setAttributes( {
    mediaUrl: src || media.url,
  } );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, we’re nearly done. As soon as a user selects an image from the placeholder, it will be placed in the block due to our conditional. As soon as &lt;code&gt;mediaUrl&lt;/code&gt; receives a value in state, it will equate to true. However, now that we have an image in our block, how do we change it?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adding a media upload control to the toolbar&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are a number of ways to handle image modification. We could add our own button over the top of the image, add something to the inspector, or, the WordPress way, we could add a control to the block’s toolbar. You probably saw that coming.&lt;/p&gt;
&lt;p&gt;We’re already importing the media components, we just need a few more. First, we bring in &lt;code&gt;BlockControls&lt;/code&gt;. It basically just acts a wrapper. In fact, &lt;a href=&quot;https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/block-controls/index.js&quot;&gt;look at the source&lt;/a&gt;, there’s hardly anything there. React is… interesting.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { BlockControls, MediaPlaceholder, MediaUpload } = wp.editor;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we need the &lt;code&gt;Toolbar&lt;/code&gt; and &lt;code&gt;IconButton&lt;/code&gt; components. They’re coming in from &lt;code&gt;wp.components&lt;/code&gt; rather than &lt;code&gt;wp.editor&lt;/code&gt; like the other components.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { Toolbar, IconButton } = wp.components;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When I began doing block development, I was confused about all of this, and wondered why all of this stuff wasn’t already available. Well, friends, that is not the case. The computer will definitely be very angry if you do not specifically bring in what you need. Do not bring someone to the party if they were not first invited.&lt;/p&gt;
&lt;p&gt;In the edit function, right above the JSX for the block, we’ll add the new &lt;code&gt;MediaUpload&lt;/code&gt; component, amongst our new components. Like so.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;BlockControls&amp;gt;
  &amp;lt;Toolbar&amp;gt;
    &amp;lt;MediaUpload
      onSelect={onSelectMedia}
      allowedTypes={[&apos;image&apos;]}
      value={mediaUrl}
      render={({ open }) =&amp;gt; (
        &amp;lt;IconButton
          className=&quot;components-toolbar__control&quot;
          label={__(&apos;Edit media&apos;)}
          icon=&quot;edit&quot;
          onClick={open}
        /&amp;gt;
      )}
    /&amp;gt;
  &amp;lt;/Toolbar&amp;gt;
&amp;lt;/BlockControls&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much of this is the same as what we did for the &lt;code&gt;MediaPlaceholder&lt;/code&gt; above. Big difference here is that we have a value attribute with the &lt;code&gt;mediaURL&lt;/code&gt; assigned to it.&lt;/p&gt;
&lt;p&gt;Of note here is the &lt;code&gt;IconButton&lt;/code&gt; component. This is what actually adds a user-interactive control to the toolbar. It needs a class of &lt;code&gt;components-toolbar__control&lt;/code&gt; to match the style of other toolbar buttons, a requirement that I hope goes away at some point.&lt;/p&gt;
&lt;p&gt;When a user engages the edit button, a media modal pops up, and then they are able to either upload a new image, or choose something else from the media library. Fancy!&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Hate to say it, but this may have been more information than one article could handle. Unfortunately, media in Gutenberg is a tricky one! I didn’t even take this as far as I very well could or should have. Below, I’ve started a short list of things I hope to explore. Hopefully I’ll be back with answers one of these days.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Questions or Improvements Remaining&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How can we output responsive image markup?&lt;/li&gt;
&lt;li&gt;How much of the image metadata should we store in our attributes? Should we add alt text?&lt;/li&gt;
&lt;li&gt;I showed how to output the image as a background. How would this be different for an image tag?&lt;/li&gt;
&lt;li&gt;Getting back to my earlier question, can we handle image uploads without the Lodash dependency? Does it matter?&lt;/li&gt;
&lt;li&gt;What if Gutenberg just did all of this for us?&lt;/li&gt;
&lt;li&gt;How do I keep all of my other life memories in my brain if they are getting crowded out by React info?&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Adding dark mode support</title><link>https://samhermes.com/posts/adding-dark-mode-support/</link><guid isPermaLink="true">https://samhermes.com/posts/adding-dark-mode-support/</guid><pubDate>Thu, 06 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I just pushed an update to my site to add support for dark mode. If a user visits the site while their device is set to prefer a dark color scheme, they&apos;ll receive a specially designed version of the site. I was inspired to dig into this after viewing a WWDC video about &lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2019/511/&quot;&gt;dark mode and web content&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&apos;s a super easy to add styles for dark mode using &lt;code&gt;prefers-color-scheme&lt;/code&gt;. A rule set in Sass would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.project-link {
  background: #282a36;

  @media (prefers-color-scheme: dark) {
    background: #fff;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the moment, the &lt;a href=&quot;https://caniuse.com/#search=prefers-color-scheme&quot;&gt;support isn&apos;t great&lt;/a&gt;. The latest versions of Safari and Firefox have it included. On the horizon, however, it appears that Chrome will be adding support. With other browsers, like Edge, taking advantage of the Chromium rendering engine, support will spread rapidly.&lt;/p&gt;
&lt;p&gt;Although the &lt;code&gt;prefers-color-scheme&lt;/code&gt; media feature (PS, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#Media_features&quot;&gt;just learned that that&apos;s what these things are called&lt;/a&gt;) is the best way to adapt styles for dark mode, there is also a &lt;code&gt;color-scheme&lt;/code&gt; style property. By adding it to the &lt;code&gt;:root&lt;/code&gt; selector, you could communicate that your entire site supports (or doesn&apos;t support) dark mode. One advantage of communicating this is that browser-based elements like form controls will adapt accordingly.&lt;/p&gt;
&lt;p&gt;The rule set for &lt;code&gt;color-scheme&lt;/code&gt; would look like this, &lt;a href=&quot;https://webkit.org/blog/8840/dark-mode-support-in-webkit/&quot;&gt;thank you webkit.org&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:root {
  color-scheme: light dark;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;color-scheme&lt;/code&gt; property is &lt;a href=&quot;https://drafts.csswg.org/css-color-adjust-1/#color-scheme-prop&quot;&gt;still in a draft&lt;/a&gt;, so I&apos;m not sure when we&apos;ll see it widely adopted. It&apos;s good to know that it&apos;s coming though, as it helps to provide full dark mode control.&lt;/p&gt;
</content:encoded></item><item><title>Controlling scroll position natively</title><link>https://samhermes.com/posts/controlling-scroll-position-natively/</link><guid isPermaLink="true">https://samhermes.com/posts/controlling-scroll-position-natively/</guid><pubDate>Mon, 22 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It had been a little while since I implemented a control to scroll the page, and I was delighted to find that much of the functionality we usually look for has been implemented directly into &lt;a href=&quot;https://caniuse.com/#feat=element-scroll-methods&quot;&gt;most of the major browsers&lt;/a&gt;! Of course, before we get too carried away, it’s important to note that this isn’t quite ready for use without a polyfill, but we’re getting closer and closer every day.&lt;/p&gt;
&lt;p&gt;The browser controls fall under the &lt;code&gt;window&lt;/code&gt; object, so we can give our directions there. The available functions are &lt;code&gt;.scroll()&lt;/code&gt;, &lt;code&gt;.scrollBy()&lt;/code&gt;, &lt;code&gt;.scrollByLines()&lt;/code&gt;, &lt;code&gt;.scrollByPages()&lt;/code&gt;, and &lt;code&gt;.scrollTo()&lt;/code&gt;. The scroll by lines and pages are hardly supported, it looks like just Firefox has picked them up for now. However, the remaining three are more than enough to get most jobs done.&lt;/p&gt;
&lt;p&gt;A common pattern that we see around is the case where the hero area of a page takes up &lt;code&gt;100vh&lt;/code&gt;, and gives the appearance of a full screen element. Some feel that users do not know to scroll, so they put a down arrow at the bottom of the hero area, which, when clicked, takes the user down the page. Usually, with this, we want to position the top of the viewport in alignment with the very bottom of the hero area.&lt;/p&gt;
&lt;p&gt;Here’s the full function for the desired behavior, and then I’ll pick it apart a bit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// store the &amp;lt;button&amp;gt; element in a variable
var downButton = document.querySelector(&apos;.down-button&apos;);

// attach event handler to the button element
downButton.addEventListener(&apos;click&apos;, function () {
  // get the pixel value of how much the user has already scrolled
  var alreadyScrolled = window.scrollY;
  // get the window&apos;s height, subtract how much the user has scrolled
  var windowHeight = window.innerHeight - alreadyScrolled;

  // smoothly scroll down the page by calculated amount
  window.scrollBy({
    left: 0,
    top: windowHeight,
    behavior: &apos;smooth&apos;
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll notice that &lt;code&gt;.scrollBy()&lt;/code&gt; is in use here. This allows us to pass in a pixel value of how much we’d like to scroll. To ensure that the user always gets take to the same spot, we need to check and makes sure that we incorporate any amount that they’ve already scrolled. We subtract that from the &lt;code&gt;innerHeight&lt;/code&gt; value that is a part of the &lt;code&gt;window&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;The best part of this functionality is the &lt;code&gt;behavior&lt;/code&gt; setting. Previously, we went looking for libraries to scroll smoothly, but now it’s built into the browser. Although it lacks customization, it works great for most cases, and eases the page to the new scroll position. You can always take a user immediately to the new scroll position if desired, but the smooth scroll helps to show exactly what’s happening.&lt;/p&gt;
&lt;p&gt;Last but not least, a polyfill is needed to make this work in IE and Edge (at least at the time of writing). There is one by Dustan Kasten, &lt;a href=&quot;https://github.com/iamdustan/smoothscroll&quot;&gt;available on GitHub&lt;/a&gt;. It gets the browser support to where most would need it to be. Hopefully we’ll be able to skip it altogether soon.&lt;/p&gt;
</content:encoded></item><item><title>Deploying a repository to a subdirectory of GitHub Pages site</title><link>https://samhermes.com/posts/deploying-repository-subdirectory-github-pages-site/</link><guid isPermaLink="true">https://samhermes.com/posts/deploying-repository-subdirectory-github-pages-site/</guid><pubDate>Sat, 20 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My site is currently hosted on GitHub Pages, which means that anytime I want to put something on the site, I have to make a commit and push it up. This works great for most things, but if I want to work on a larger project and “host” it on my site, it has to all go in the same repo. With GitHub Pages, it wasn’t clear that there is a much easier way to handle this. It’s a simple as setting any other repository to use GitHub Pages as well.&lt;/p&gt;
&lt;p&gt;When you set up the first GitHub Pages repository, you’re given subdomain at a github.io address. This acts as the main or parent site. In my case, I took this a little further by setting up a custom domain, which isn’t required but works just the same. After the main site is set up, any additional repositories that have GitHub pages enabled on them will use a subdirectory structure. These are referred to as “project pages.” The GitHub documentation is a little fuzzy on what exactly that means, but it’s just that these are deployed to a subdirectory of the main site.&lt;/p&gt;
&lt;p&gt;I made a repository called &lt;code&gt;test-subdirectory&lt;/code&gt;, which had a sample index file in it. I pushed this repo to GitHub, and in the repository settings, I chose a source branch under the GitHub Pages section. This immediately deployed the repository to &lt;a href=&quot;https://samhermes.github.io/test-subdirectory&quot;&gt;samhermes.github.io/test-subdirectory&lt;/a&gt;. Now, I no longer need to keep all of my projects within the main repository.&lt;/p&gt;
&lt;p&gt;It’s very likely that this is something that is obvious to other people, but it’s something that just wasn’t very clear to me, even after searching around for information. Sometimes something so simple can turn into an unnecessary hurdle.&lt;/p&gt;
</content:encoded></item><item><title>Asking for feedback</title><link>https://samhermes.com/posts/asking-for-feedback/</link><guid isPermaLink="true">https://samhermes.com/posts/asking-for-feedback/</guid><pubDate>Thu, 28 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Feedback is a topic that comes up all the time when working with a team. I definitely know its value and appreciate it when it comes, but it’s difficult to both remember to ask for it and to stay open to it.&lt;/p&gt;
&lt;p&gt;First off, asking for someone’s opinion of your work can be pretty scary, and very easy to avoid as well. If you don’t ask, you won’t find out that it’s bad. Why would you punish yourself? Like most things, my default around this seems to be remaining quiet. The problem with this is that feedback helps us grow, and growing is good. It helps us do better next time.&lt;/p&gt;
&lt;p&gt;One of the biggest things that I’ve found to help is to ask very specifically for it. After a meeting is over, asking your supervisor about how they thought you did. Or, after a presentation, sending a Slack message to a few key individuals to ask about how it went. Small, specific bits of feedback are super helpful and easy for someone else to give. Asking someone about how good you are at your job in general is a very tricky thing to answer.&lt;/p&gt;
&lt;p&gt;Taking this further, it’s good to ensure that space is left for feedback. Oftentimes, feedback is requested in a group setting, which isn’t a very good forum for honest feedback. An asynchronous way to send in feedback at someone’s own pace is much better, whether that’s just an email or Slack message. I think that sometimes we’re scared of getting too much feedback, especially if we’re leaving it open to an entire group of people, but more feedback is always better!&lt;/p&gt;
&lt;p&gt;Asking for feedback is good, but getting unsolicited feedback is better! One thing I really appreciate is when someone takes the time to comment on how I did. It’s really nice to receive, but can be difficult to give. You can really make someone’s day if you give them positive reinforcement. I haven’t found a good, structured of going about this, but sometimes it’s the spontaneity that makes it special anyhow.&lt;/p&gt;
&lt;p&gt;After everything that I’ve said here, I would also like to look at this in the opposite way. Sometimes, too much feedback is bad. And, if we’re constantly evaluating how someone else is doing at something, we miss the valiant effort that they made to begin with. No one is running at 100% all the time. It’s when you’re having a bad day that you really don’t want to give or receive feedback. If I’m having a bad day, I’m unimpressed with everyone else, and that’s just not my true feeling. That’s more about my bad day. It’s good to remember that feedback has its proper time and place.&lt;/p&gt;
</content:encoded></item><item><title>Excluding Uncategorized when listing categories in WordPress</title><link>https://samhermes.com/posts/excluding-uncategorized-listing-categories-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/excluding-uncategorized-listing-categories-wordpress/</guid><pubDate>Fri, 15 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ah, the eternal dilemma. What’s the best way to show a list of categories without including the “Uncategorized” category that WordPress generates by default? I feel like I re-solve this issue each time that it comes up. The issue is that categories can be listed in a couple different contexts, so the solution differs. Sometimes we’re listing all of them on the site or sometimes we’re listing them for the current post. Let’s solve this once and for all!&lt;/p&gt;
&lt;h2&gt;For the current post&lt;/h2&gt;
&lt;p&gt;Whether displayed in an archive or in the single post template, this is when we’re listing categories for a specific post.&lt;/p&gt;
&lt;p&gt;The best way to list post categories is &lt;code&gt;get_the_category()&lt;/code&gt;. It actually returns all categories, despite what its name may imply. Normally, you could use &lt;code&gt;get_the_category_list()&lt;/code&gt;, but we need to do a little modification before outputting.&lt;/p&gt;
&lt;p&gt;Place this function in your &lt;code&gt;functions.php&lt;/code&gt; file, or in the commonly-used &lt;code&gt;template-tags.php&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function custom_get_the_category_list() {
  $categories = get_the_category();
  $uncategorized_id = get_cat_ID( &apos;Uncategorized&apos; );
  $categories_list = &apos;&apos;;

  foreach ( $categories as $category ) {
    if ( $category-&amp;gt;category_parent == $uncategorized_id
          || $category-&amp;gt;cat_ID == $uncategorized_id ) {
      continue;
    }
    $categories_list .=
      &apos;&amp;lt;li&amp;gt;&amp;lt;a href=&quot;&apos; . get_category_link( $category-&amp;gt;cat_ID ) . &apos;&quot;&amp;gt;&apos; .
      $category-&amp;gt;name .
      &apos;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&apos;;
  }

  return &apos;&amp;lt;ul class=&quot;post-categories&quot;&amp;gt;&apos; . $categories_list . &apos;&amp;lt;/ul&amp;gt;&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing to call out about this function is that it checks for both Uncategorized itself and any children of Uncategorized. This may vary in your project, but it seems a safe assumption to make.&lt;/p&gt;
&lt;p&gt;Now you can just use &lt;code&gt;custom_get_the_category_list()&lt;/code&gt; anywhere that you would use &lt;code&gt;get_the_category_list()&lt;/code&gt;. Note for the beginner, it’s best to substitute the name of your project for &lt;code&gt;custom&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;For all posts&lt;/h2&gt;
&lt;p&gt;Listing all of the categories on a site is very similar to listing them for a single post. Instead of &lt;code&gt;get_the_category()&lt;/code&gt;, we use &lt;code&gt;get_categories()&lt;/code&gt;. The naming makes a little more sense this time. Again, normally you could just use &lt;code&gt;wp_list_categories()&lt;/code&gt;, and you’d get an unordered list of categories that included Uncategorized.&lt;/p&gt;
&lt;p&gt;Place this function in your &lt;code&gt;functions.php&lt;/code&gt; file, or in the commonly-used &lt;code&gt;template-tags.php&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function custom_list_categories() {
    $categories = get_categories();
    $uncategorized_id = get_cat_ID( &apos;Uncategorized&apos; );
    $categories_list = &apos;&apos;;

    foreach ( $categories as $category ) {
        if ( $category-&amp;gt;category_parent == $uncategorized_id
                || $category-&amp;gt;cat_ID == $uncategorized_id ) {
            continue;
        }
        $categories_list .=
            &apos;&amp;lt;li&amp;gt;&amp;lt;a href=&quot;&apos; . get_category_link( $category-&amp;gt;cat_ID ) . &apos;&quot;&amp;gt;&apos; .
            $category-&amp;gt;name .
            &apos;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&apos;;
    }

    return &apos;&amp;lt;ul class=&quot;site-categories&quot;&amp;gt;&apos; . $categories_list . &apos;&amp;lt;/ul&amp;gt;&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can just use &lt;code&gt;custom_list_categories()&lt;/code&gt; anywhere that you would use &lt;code&gt;wp_list_categories()&lt;/code&gt;. Note for the beginner, it’s best to substitute the name of your project for &lt;code&gt;custom&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Notes from WordCamp US 2018</title><link>https://samhermes.com/posts/notes-from-wordcamp-us/</link><guid isPermaLink="true">https://samhermes.com/posts/notes-from-wordcamp-us/</guid><pubDate>Thu, 13 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;h2 class=&quot;margin-bottom-zero&quot;&amp;gt;Thinking Like a Front-End Developer&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chris Coyier&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;During Chris’s talk, I pushed a &lt;a href=&quot;https://github.com/samhermes/samhermes.github.io/commit/d6a66519092adee0376a1f748f27964551846e0a&quot;&gt;very small commit&lt;/a&gt; to my website to change “front end” to “front-end.” I agreed with &lt;a href=&quot;https://twitter.com/WordCampUS/status/1071065672313118720&quot;&gt;his explanation&lt;/a&gt; of when to use which, even though it was different from the convention that I’d been using for a while.&lt;/p&gt;
&lt;p&gt;I found his talk very fun to listen to, and appreciated how he acknowledged the vast amount of responsibility that we all have to shoulder in our jobs. There was a feeling of togetherness in the room.&lt;/p&gt;
&lt;p&gt;One intriguing idea that Chris spoke about was the idea of &quot;front of the front end&quot; vs &quot;back of the front end.&quot; He got this from &lt;a href=&quot;https://shoptalkshow.com/episodes/334/&quot;&gt;speaking with Brad Frost on the ShopTalk Show&lt;/a&gt;, and I think that it points to a natural divide that is happening. With React, working on the front end can actually end up looking a little like working on the back end. I’ve traditionally been more of a “front of the front” kind of developer.&lt;/p&gt;
&lt;p&gt;&amp;lt;h2 class=&quot;margin-bottom-zero&quot;&amp;gt;Holy Blockamole: Tips On Learning Block Development&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Andrew Taylor&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Andrew’s lightning talk gave a high-level overview of the ways that developers can work with Gutenberg, from creating templates to block development.&lt;/p&gt;
&lt;p&gt;When working in a custom post type, it’s easy to set a pre-defined set of blocks and prevent a user from adding or removing them. This can be done by setting &lt;code&gt;&apos;template_lock&apos; =&amp;gt; &apos;all&apos;&lt;/code&gt;. You can set the specific blocks fairly simply using &lt;code&gt;template&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;template&apos; =&amp;gt; array (
  array( &apos;core/heading&apos;, array(
    &apos;placeholder&apos; =&amp;gt; __( &apos;Title...&apos;, &apos;my-plugin&apos; ),
    &apos;level&apos; =&amp;gt; 4,
  ) ),
  array( &apos;core/image&apos;, array(
    // Any block atribute can be set as the default.
    &apos;align&apos; =&amp;gt; &apos;wide&apos;,
  ) ),
  array( &apos;core/paragraph&apos;, array(
    &apos;placeholder&apos; =&amp;gt; __( &apos;Bio...&apos;, &apos;my-plugin&apos; ),
  ) ),
),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I took this code directly from &lt;a href=&quot;https://drive.google.com/file/d/1nX3xwOeH9Q5v9y-KDKEgffHRdzJRvoLG/view&quot;&gt;Andrew’s slides&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The question that this posed, for me, was how would we set this up if our blocks were coming from a separate plugin. So, if it was possible that the blocks weren’t available, would this fall back gracefully?&lt;/p&gt;
&lt;p&gt;In general, as more of the content in our sites becomes dependent on an array of plugins, how can we be sure that it all meshes well? Likely less of an issue than I think it is, but it will be interesting to see how it plays out in real life.&lt;/p&gt;
&lt;p&gt;&amp;lt;h2 class=&quot;margin-bottom-zero&quot;&amp;gt;Investigating Regressions Quickly using Git Bisect&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;John Blackbourn&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;John explained very succinctly how to use &lt;code&gt;git bisect&lt;/code&gt;, a tool for finding the place in your commit history where an issue was introduced. By cutting the number of commits in half each time, you can get down to the issue very quickly, even if there are a hundred or so commits.&lt;/p&gt;
&lt;p&gt;Getting this started looks like this:&amp;lt;br&amp;gt;
&lt;code&gt;git bisect start&lt;/code&gt;&amp;lt;br&amp;gt;
&lt;code&gt;git bisect good &quot;2.6.10&quot;&lt;/code&gt; - commit where it worked&amp;lt;br&amp;gt;
&lt;code&gt;git bisect bad HEAD&lt;/code&gt; - where it was broken (likely the latest commit)&lt;/p&gt;
&lt;p&gt;It then guides you through until you find the bad commit. &lt;a href=&quot;https://speakerdeck.com/johnbillion/investigating-regressions-quickly-using-git-bisect&quot;&gt;John’s slides&lt;/a&gt; go into more detail about this. Like he said, I hope I never need to use this, but it’s nice to know that it’s there to help.&lt;/p&gt;
&lt;p&gt;&amp;lt;h2 class=&quot;margin-bottom-zero&quot;&amp;gt;Gutenberg, GraphQL and Government: Building Blocks&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jason Bahl&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Jason &lt;a href=&quot;https://docs.google.com/presentation/d/1PwXjxpqbZcWBKD2xTPmuJlScJiiuOHZurVyB9vR-BH4/edit#slide=id.g4846d628b1_0_566&quot;&gt;answered a question&lt;/a&gt; that had popped up during Andrew’s talk earlier. Andrew had spoken about how to limit blocks in a custom post type, but I wondered how this would be done for pages or posts. With a filter!&lt;/p&gt;
&lt;p&gt;This checks to see if the current page template is &lt;code&gt;home.php&lt;/code&gt;, and then only allows the &lt;code&gt;homepage-hero&lt;/code&gt;, &lt;code&gt;curated-posts&lt;/code&gt;, and &lt;code&gt;curated-staff&lt;/code&gt; blocks.&lt;/p&gt;
&lt;p&gt;Last but not least, it locks down the blocks using &lt;code&gt;template_lock&lt;/code&gt;, like Andrew had demonstrated. So, the user can only use the three blocks specified.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_filter( &apos;allowed_block_types&apos;, function( $allowed ) {
  global $wp_post_types, $post;
  if ( &apos;templates/home.php&apos; === get_page_template_slug( $post-&amp;gt;ID ) ) {
    $wp_post_types[ $post-&amp;gt;post_type ]-&amp;gt;template = [
      [ &apos;wcus/homepage-hero&apos; ],
      [ &apos;wcus/curated-posts&apos; ],
      [ &apos;wcus/curated-staff&apos; ],
    ];
    $wp_post_types[ $post-&amp;gt;post_type ]-&amp;gt;template_lock = &apos;all&apos;;
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h2 class=&quot;margin-bottom-zero&quot;&amp;gt;Who’s afraid of ARIA?&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Rian Rietveld&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I feel like I could make an entire post just about this talk. I love a good code demo, and this talk had lots of them. Rian made everything seem very simple and straightforward, which is refreshing when you’re talking about accessibility. In practice, I know that things get a little more complicated, but I learned a lot, nonetheless.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;aria-expanded&lt;/code&gt;&amp;lt;br&amp;gt;
This attribute is useful for menus or accordions, so that you can communicate that the following element is either hidden or visible. You would then toggle &lt;code&gt;aria-expanded&lt;/code&gt; and the hidden attribute with JavaScript when the user opens or closes the menu or accordion.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;aria-live&lt;/code&gt;&amp;lt;br&amp;gt;
This was the most interesting bit, as I think that this is difficult to get right. &lt;code&gt;aria-live&lt;/code&gt; is used to tell the user about what’s changing on the screen. So, if they hit a button to save changes, we should tell them when the changes have been successfully saved.&lt;/p&gt;
&lt;p&gt;Initially, the element with the message in it would have &lt;code&gt;aria-live=&quot;polite&quot;&lt;/code&gt; applied to it. Using JavaScript, we would update that to &lt;code&gt;aria-live=&quot;assertive&quot;&lt;/code&gt;, triggering the screen reader to read it out.&lt;/p&gt;
&lt;p&gt;Similarly, if we have an ajax search feature, we could use this method to announce when new search results arrive with a message such as &quot;There are 24 search results.”&lt;/p&gt;
&lt;p&gt;WordPress has functionality built into it that handles this for you. &lt;code&gt;wp.a11y.speak()&lt;/code&gt; will add two &lt;code&gt;div&lt;/code&gt;s to the bottom of the page, one with &lt;code&gt;aria-live=&quot;polite&quot;&lt;/code&gt; and one with &lt;code&gt;aria-live=&quot;assertive&quot;&lt;/code&gt; and update them as appropriate.&lt;/p&gt;
&lt;p&gt;I highly recommend watching Rian’s talk when it becomes available.&lt;/p&gt;
&lt;p&gt;&amp;lt;h2 class=&quot;margin-bottom-zero&quot;&amp;gt;Product Design Through Stories&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tammie Lister&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Just a few select quotes to share from &lt;a href=&quot;https://speakerdeck.com/tammielis/product-design-through-stories&quot;&gt;Tammie’s talk&lt;/a&gt;, which may or may not be paraphrased. Life moves fast.&lt;/p&gt;
&lt;p&gt;“We are, as a species, addicted to story. Even when the body goes to sleep, the mind stays up all night, telling itself stories.” —Jonathan Gottschall&amp;lt;br&amp;gt;
“Products with stories are powerful. When the story is good, the bond with the product is strong.”&amp;lt;br&amp;gt;
“It’s important that everyone creating the product is involved in telling the story.”&lt;/p&gt;
&lt;p&gt;Tammie made the point that a product has several different stories surrounding it. There are those people who use the product, the people who make the product, and the effect the product has by existing. Not only do you want to be aware of the story that the product is telling others, you also want to maintain the story internally.&lt;/p&gt;
&lt;p&gt;&quot;Being too fast can be as bad as being too slow.”&lt;/p&gt;
&lt;p&gt;This was an idea that caught my attention. Sometimes, a process can happen so quickly that it overwhelms a user. Maybe they miss what happened because you gave them too much information at once, or you used too many channels to communicate.&lt;/p&gt;
&lt;p&gt;I’d recently learned about the idea of setting a minimum loading time on an ajax request, so that it doesn’t come back too quickly, and I think this connects to Tammie’s point. If something is too quick, you lose a little trust. Like, maybe it didn’t try hard enough. For human speed, maybe inflating the loading time just a touch will actually make the experience feel more robust.&lt;/p&gt;
&lt;p&gt;If you happen to be using a poor connection, this is likely the opposite of a problem, but still worth thinking about for those users with speedy connections.&lt;/p&gt;
&lt;p&gt;Last, but not least:&lt;/p&gt;
&lt;p&gt;“The details are not the details. They make the design.” —Charles Eames&lt;/p&gt;
</content:encoded></item><item><title>Disabling blocks and block styles in Gutenberg</title><link>https://samhermes.com/posts/disabling-blocks-block-styles-gutenberg/</link><guid isPermaLink="true">https://samhermes.com/posts/disabling-blocks-block-styles-gutenberg/</guid><pubDate>Wed, 28 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As with most things involving Gutenberg, this could change, and may not be best practice later on, but it&apos;s what I&apos;ve found to work for the time being. Both blocks and block styles can be disabled through JavaScript, using &lt;code&gt;wp.domReady()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First things first, a JavaScript file needs to be enqueued in the Gutenberg editor, which can be accomplished by hooking into &lt;code&gt;enqueue_block_editor_assets&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function namespace_block_editor_scripts() {
  wp_enqueue_script( &apos;namespace-core-blocks&apos;, &apos;core-blocks.js&apos;, array( &apos;wp-blocks&apos; ), &apos;&apos;, true );
}
add_action( &apos;enqueue_block_editor_assets&apos;, &apos;namespace_block_editor_scripts&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside of &lt;code&gt;core-blocks.js&lt;/code&gt;, it&apos;s fairly simple to disable blocks and block styles. The tricky part is knowing how they are named, which can take some digging. My example only disables the Verse and Cover blocks, and the &quot;Dots&quot; option in the Separator block. Take note of the two &lt;code&gt;unregisterBlockType&lt;/code&gt; and &lt;code&gt;unregisterBlockStyle&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wp.domReady(() =&amp;gt; {
  wp.blocks.unregisterBlockType(&apos;core/verse&apos;);
  wp.blocks.unregisterBlockType(&apos;core/cover&apos;);

  wp.blocks.unregisterBlockStyle(&apos;core/separator&apos;, &apos;dots&apos;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Based on the discussion happening in &lt;a href=&quot;https://github.com/WordPress/gutenberg/issues/11338&quot;&gt;issue #11338&lt;/a&gt; on Github, &lt;code&gt;wp.domReady()&lt;/code&gt; seems to be the best place to unregister block types and styles at the moment, though it may not be necessary in the future. It would also be nice to control this in PHP, which may eventually be an option as well.&lt;/p&gt;
&lt;p&gt;Like I said before, things with Gutenberg are actively changing. I&apos;ll be keeping this post updated with the latest information as I learn it. If you know of a better, more official way, do &lt;a href=&quot;https://samhermes.typeform.com/to/d4C4FT&quot;&gt;let me know&lt;/a&gt;!&lt;/p&gt;
</content:encoded></item><item><title>Replacing Moment.js with date-fns</title><link>https://samhermes.com/posts/replacing-moment-js-date-fns/</link><guid isPermaLink="true">https://samhermes.com/posts/replacing-moment-js-date-fns/</guid><pubDate>Thu, 15 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my &lt;a href=&quot;https://samhermes.github.io/next-spacex-launch/&quot;&gt;Next SpaceX Launch&lt;/a&gt; app, data is pulled from a &lt;a href=&quot;https://github.com/r-spacex/SpaceX-API&quot;&gt;SpaceX API&lt;/a&gt;. It returns date and time information for each launch, which needs to be formatted before being displayed. When I started on this project, I quickly found Moment.js and determined that it could get the job done. It was easy to format a date with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Moment format=&quot;MMMM DD, YYYY&quot;&amp;gt;{ mission.launch_date_local }&amp;lt;/Moment&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This accepts the date and time string and returns a formatted date in &lt;code&gt;MMMM DD, YYYY&lt;/code&gt; format. Using this for time is similar, just passing in &lt;code&gt;h:mm a&lt;/code&gt; as the format.&lt;/p&gt;
&lt;p&gt;The issue with using Moment.js for this is that it’s just simply overkill, as demonstrated by the &lt;a href=&quot;https://github.com/you-dont-need/You-Dont-Need-Momentjs&quot;&gt;You-Dont-Need-Momentjs&lt;/a&gt; repo. In my simple application, I’m merely wanting to format a handful of dates. Passing Moment.js off to the user means that they are loading extra code in the browser unnecessarily. Fortunately, there’s a simpler library, &lt;code&gt;date-fns&lt;/code&gt; that gets the job done in much the same way.&lt;/p&gt;
&lt;p&gt;I uninstalled &lt;code&gt;react-moment&lt;/code&gt; and &lt;code&gt;moment&lt;/code&gt; from my project, and then installed &lt;code&gt;date-fns&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm uninstall react-moment
$ npm uninstall moment
$ npm install date-fns
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I then updated the import statement inside of each component.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import format from &apos;date-fns/format&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, in the app, in the places where I was using &lt;code&gt;&amp;lt;Moment&amp;gt;&lt;/code&gt;, I swapped it out for &lt;code&gt;format()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ format( mission.launch_date_local, &apos;MMMM DD, YYYY&apos; ) }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple as that! In the end, the end user gets a completed page a little quicker, with the exact same functionality.&lt;/p&gt;
</content:encoded></item><item><title>Upgrading from Gulp 3 to 4</title><link>https://samhermes.com/posts/upgrading-from-gulp-3-to-4/</link><guid isPermaLink="true">https://samhermes.com/posts/upgrading-from-gulp-3-to-4/</guid><pubDate>Sun, 11 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We love when things just keep getting better! Gulp 4 has many new features, and with just a few changes to &lt;code&gt;gulpfile.js&lt;/code&gt;, it’s easy to make the upgrade. Gulp 4 was officially released on December 31, 2017.&lt;/p&gt;
&lt;p&gt;The biggest change is in how tasks are ordered. Previously, if there was a list of tasks that you wanted to complete, they would happen sequentially. Now, with a mixture of &lt;code&gt;gulp.series()&lt;/code&gt; and &lt;code&gt;gulp.parallel()&lt;/code&gt;, you can be a little more specific. &lt;code&gt;gulp.series()&lt;/code&gt; will complete tasks sequentially, like before, and &lt;code&gt;gulp.parallel()&lt;/code&gt; will complete them at the same time.&lt;/p&gt;
&lt;p&gt;Let’s look at a 1 to 1 conversion. These are the changes I needed to make to my watch task, just to get things working like they were in Gulp 3.&lt;/p&gt;
&lt;p&gt;For my watch task, I had:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gulp.task(&apos;watch&apos;, function () {
  gulp.watch(&apos;./sass/**/*.scss&apos;, [&apos;sass&apos;]);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The change that needs to be made here is with the &lt;code&gt;[&apos;sass&apos;]&lt;/code&gt; array. This defines which tasks should run when the watch tasks detects a change to any &lt;code&gt;.scss&lt;/code&gt; file in the &lt;code&gt;sass&lt;/code&gt; folder or any of its children. Since there is only one task to run, we can use &lt;code&gt;gulp.series()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gulp.watch(&apos;./sass/**/*.scss&apos;, gulp.series(&apos;sass&apos;));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a simple change, and things get only a little more complicated when there is more than one task to run. In my case, it was the &lt;code&gt;default&lt;/code&gt; task. In it, I run the &lt;code&gt;sass&lt;/code&gt; task, and then start the &lt;code&gt;watch&lt;/code&gt; task.&lt;/p&gt;
&lt;p&gt;Previously, it looked like this, a simple array:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gulp.task(&apos;default&apos;, [&apos;sass&apos;, &apos;watch&apos;]);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we use &lt;code&gt;gulp.parallel()&lt;/code&gt; to accomplish the same result. This just means that these two tasks are free to run at the same time, as they are not dependent on one another.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gulp.task(&apos;default&apos;, gulp.parallel(&apos;sass&apos;, &apos;watch&apos;));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that &lt;code&gt;gulpfile.js&lt;/code&gt; is up to date and ready for Gulp 4, it’s time to actually do the upgrade. This is straightforward with &lt;code&gt;npm&lt;/code&gt;. The following commands upgrade the global Gulp installation, by first removing the old version and then installing new.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://github.com/pattern-lab/edition-node-gulp/wiki/Updating-to-Gulp-4&quot;&gt;this note in the Pattern Lab repo&lt;/a&gt;, “Gulp 4 uses an updated CLI which needs to be updated globally. This CLI is backwards compatible with any Gulp 3.X projects you may have locally.”&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm rm -g gulp
$ npm install -g gulp-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that Gulp is upgraded globally, each individual project needs to be updated to take advantage of it. Just like the global upgrade, the following commands uninstall the local version and then install the new.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm uninstall gulp --save-dev
$ npm install gulp@^4.0.0 --save-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re off to the races!&lt;/p&gt;
</content:encoded></item><item><title>How to add multiple default markers with popups in Mapbox GL JS</title><link>https://samhermes.com/posts/multiple-markers-popups-mapbox/</link><guid isPermaLink="true">https://samhermes.com/posts/multiple-markers-popups-mapbox/</guid><pubDate>Wed, 10 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To create my travel map, I used Mapbox GL JS. After the map embed loads from Mapbox, it fires off an ajax request to a WordPress site where the location data is stored. The map gets the response in JSON, which is then used to build a geoJSON object that the map will understand. From there, adding the data to the map is fairly easy, if you know what you’re doing.&lt;/p&gt;
&lt;p&gt;Adding a single marker to a Mapbox embed is straightforward. The Mapbox documentation site provides a &lt;a href=&quot;https://www.mapbox.com/mapbox-gl-js/api/#marker&quot;&gt;working example&lt;/a&gt; that can be emulated, but doesn’t give explicit instructions for what to do if you have multiple points. In my case, I also wanted to add a popup for each of the markers with a title and visit count.&lt;/p&gt;
&lt;p&gt;Now that I’m on the other side of this issue, it seems so straightforward. In order to get here, though, I used a &lt;a href=&quot;https://www.mapbox.com/help/demos/gl-store-locator/step-five.html&quot;&gt;store locator demo from Mapbox&lt;/a&gt;. It’s slightly more complicated than what I was looking for, but it contained the structure that I was looking for. If you open the inspector on that page, there’s a script tag at the bottom of the page that contains the relevant JS.&lt;/p&gt;
&lt;p&gt;To add more than one marker, all that’s needed is a &lt;code&gt;forEach&lt;/code&gt; loop. If coming from geojson, you can loop over the &lt;code&gt;features&lt;/code&gt; array. In the store locator demo, that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stores.features.forEach(function(marker) { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within the forEach, it’s simple to create a new marker for each point in the &lt;code&gt;features&lt;/code&gt; array.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;new mapboxgl.Marker()
  .setLngLat(marker.geometry.coordinates)
  .addTo(map);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The store locator example, like all of the others provided by Mapbox, uses a custom icon for each marker. I prefer the default Mapbox marker style, so the part of the demo where it creates an empty div for each marker is unnecessary, and actually removes the default icon when set in the &lt;code&gt;new mapboxgl.marker&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;To add a popup to each marker, there are a number of ways to go about it. This was confusing to me at first, as some demos show a way to use just one popup, and update it as each marker is clicked on or activated. This is not necessary, as you can create a popup for each marker, and the map handles the display.&lt;/p&gt;
&lt;p&gt;Above the &lt;code&gt;new mapboxgl.Marker()&lt;/code&gt; call above, building a popup is done very similarly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var popup = new mapboxgl.Popup()
  .setText(marker.properties.title);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a popup created, a slight modification to the marker setup will ensure that the popup is attached to the appropriate marker.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;new mapboxgl.Marker()
  .setLngLat(marker.geometry.coordinates)
  .setPopup(popup)
  .addTo(map);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An archived, working version of this code can be &lt;a href=&quot;https://github.com/samhermes/samhermes.github.io/blob/e03be05ef9544bf4f5bc7d13b93c9ac709354cd9/js/travel-map.js&quot;&gt;seen on Github&lt;/a&gt;, where I customize the popup styles a bit.&lt;/p&gt;
</content:encoded></item><item><title>Preparing a WordPress theme for Gutenberg</title><link>https://samhermes.com/posts/preparing-wordpress-theme-gutenberg/</link><guid isPermaLink="true">https://samhermes.com/posts/preparing-wordpress-theme-gutenberg/</guid><pubDate>Sun, 12 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As the launch of Gutenberg gets closer and closer, now is as good a time as any to make preparations. My theme that is live in the theme directory, &lt;a href=&quot;https://wordpress.org/themes/halle/&quot;&gt;Halle&lt;/a&gt;, works fairly well with Gutenberg without any changes, but there are some small modifications that I’d like to make to improve the overall experience and to take full advantage of what Gutenberg offers.&lt;/p&gt;
&lt;h2&gt;Matching editor styles to the front end&lt;/h2&gt;
&lt;p&gt;Gutenberg is fantastic for the way it allows the back end editing experience to mirror the front end display, if you desire. With some slight modifications, it’s really easy to bring the styles into alignment. Just to start, you can register the same Google Fonts in the editor.&lt;/p&gt;
&lt;p&gt;This is fairly similar to the &lt;code&gt;wp_enqueue_scripts&lt;/code&gt; action that is typically used for front end styles, the difference is that &lt;code&gt;enqueue_block_editor_assets&lt;/code&gt; just enqueues the styles in the Gutenberg editor.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function halle_block_editor_styles() {
  wp_enqueue_style( &apos;halle-editor-fonts&apos;, &apos;https://fonts.googleapis.com/css?family=Work+Sans:400,500,700|Poly:400,400i&apos; );
}
add_action( &apos;enqueue_block_editor_assets&apos;, &apos;halle_block_editor_styles&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Previously, I was adding Google fonts to the editor using &lt;code&gt;add_editor_style( )&lt;/code&gt; and passing in the stylesheet URL. As some users will still be using the classic editor, and some will use Gutenberg, I’ll leave both of these in place. I’m not sure when I’ll be able to remove the old &lt;code&gt;add_editor_style()&lt;/code&gt; declaration, but I’d say that I would leave it in for a year or so as users upgrade and transition.&lt;/p&gt;
&lt;p&gt;Now that the fonts are enqueued, we need to use them for the post/page title and other text blocks. I created a new Sass file called &lt;code&gt;block-editor-styles.scss&lt;/code&gt; in the theme, and enqueued it inside of the &lt;code&gt;halle_block_editor_styles()&lt;/code&gt; function that I used above.&lt;/p&gt;
&lt;p&gt;Taking a cue from the &lt;a href=&quot;https://wordpress.org/gutenberg/handbook/extensibility/theme-support/#editor-styles&quot;&gt;Gutenberg Handbook&lt;/a&gt;, I started with a parent selector of &lt;code&gt;body.block-editor-page&lt;/code&gt;, and then nested all of the following styles within.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.edit-post-visual-editor {
  font-family: &apos;Poly&apos;, serif;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.edit-post-visual-editor&lt;/code&gt; class is a parent class for the editor, so this font family declaration cascades down into most elements in the editor. Gutenberg’s styles are taking the same approach, so overriding using this method is easy.&lt;/p&gt;
&lt;p&gt;Although the cascade works fairly well, both the post title and paragraphs need just a bit more specificity to override. Again, these are both nested inside of &lt;code&gt;body.block-editor-page&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.editor-post-title__input,
p {
  font-family: &apos;Poly&apos;, serif;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could go further with these styles, but your theme will likely differ from mine. The next item that I addressed was the &lt;code&gt;max-width&lt;/code&gt; of each block. You can see how I accomplished this and some other modifications &lt;a href=&quot;https://github.com/samhermes/halle/blob/gutenberg/sass/block-editor-style.scss&quot;&gt;in the Halle repo on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Customizing block styles&lt;/h2&gt;
&lt;p&gt;Out of the box, Gutenberg provides a range of blocks. By default, Gutenberg serves a new core blocks stylesheet to the front of your site to properly style each block. At the moment, the handbook states that these styles are an opt-in feature, but that doesn’t seem to be the case, as they are being served up without any additional action.&lt;/p&gt;
&lt;p&gt;At the moment, blocks will generally look the same in both the editor and the front end, but they likely will not fit with the style of your theme. Handling this will vary by instance. I am going to start with what Gutenberg offers and slightly modify from there. Fortunately, Gutenberg has block-specific classes that it applies to each element, so any styles that I add will not interfere with anyone who does not yet have Gutenberg in use.&lt;/p&gt;
&lt;p&gt;For now, I am just modifying a few blocks, as these seem to be the most opinionated (as far as styles go) of the core blocks.&lt;/p&gt;
&lt;h3&gt;Button&lt;/h3&gt;
&lt;p&gt;The button block has a number of options associated with it, but I primarily wanted to reduce the border radius (everything is so round now?!). This was accomplished by using &lt;code&gt;.wp-block-button.wp-block-button__link&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Block Quote&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;blockquote&lt;/code&gt; styles provided by Gutenberg aren’t too specific, but in my case, I needed to add support for the &lt;code&gt;blockquote&lt;/code&gt; citation that is now available. Previously, I was relying on the bottom margin of the &lt;code&gt;blockquote&lt;/code&gt; paragraph element, and needed to shift that to the &lt;code&gt;blockquote&lt;/code&gt; element itself.&lt;/p&gt;
&lt;h3&gt;Horizontal Rule&lt;/h3&gt;
&lt;p&gt;Gutenberg offers three &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; styles: short line, wide line, and dots. Previously, I was using a background color to provide the rule, but this interferes with how Gutenberg styles rules. I transitioned my styles from &lt;code&gt;background: #ccc&lt;/code&gt; to &lt;code&gt;border-top: 1px solid #ccc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The confusing part here is that Gutenberg defaults to the short line style, but currently doesn’t serve styles for it to the front end, only for the wide line and dots styles. So, if nothing is done, the short and wide lines look the same on the front end. I’ve added styles to Halle’s stylesheet to remedy this.&lt;/p&gt;
&lt;h2&gt;Enabling wide images&lt;/h2&gt;
&lt;p&gt;Wide images are the biggest reason to revisit the layout of your theme. In Halle, individual posts have a sidebar when the screen is wide enough to accommodate it. This is not conducive to wide images. This led me to question whether or not I could make the layout an option, so that the user could choose the sidebar layout, or a centered layout.&lt;/p&gt;
&lt;p&gt;To enable wide images, all that is required is the following, added to &lt;code&gt;after_setup_theme&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_theme_support( &apos;align-wide&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are several approaches to take to support wide images on the front end. You could make the parent element of the post content 100% width, and then place a &lt;code&gt;max-width&lt;/code&gt; on everything except for wide images. Or, instead, you could break the wide images out of the container. This method is described in &lt;a href=&quot;https://www.billerickson.net/getting-your-theme-ready-for-gutenberg/&quot;&gt;this article from Bill Erickson&lt;/a&gt;. I prefer the former approach.&lt;/p&gt;
&lt;p&gt;I haven’t implemented wide images in Halle yet, as this will involve much deeper changes to the foundational layout of the theme, and there’s already enough change happening. I’ll come back to this at a later time.&lt;/p&gt;
&lt;h2&gt;Color palettes&lt;/h2&gt;
&lt;p&gt;If your theme contains a specific color palette, or you are working with brand colors, customizing the color palette available to users is a great way to encourage consistency. I won’t go into how to accomplish this specifically, but it’s worth noting that this is available. More information is detailed in the &lt;a href=&quot;https://wordpress.org/gutenberg/handbook/extensibility/theme-support/#block-color-palettes&quot;&gt;Gutenberg Handbook&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Using pagination with the WordPress API in Vue</title><link>https://samhermes.com/posts/using-pagination-wordpress-api-vue/</link><guid isPermaLink="true">https://samhermes.com/posts/using-pagination-wordpress-api-vue/</guid><pubDate>Wed, 25 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a continuation of my &lt;a href=&quot;https://samhermes.com/posts/adding-pagination-in-vue/&quot;&gt;previous Vue pagination post&lt;/a&gt; in which I added pagination to the list of books that I’m reading or have read. In that post, I fetched all of the books from a specific category using the WordPress REST API, and then stored them in state. This worked great, but wasn’t a great long-term solution. The problem lies in the fact that the &lt;a href=&quot;https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/&quot;&gt;API limits queries to 100&lt;/a&gt; posts at a time by default. This means that as soon as I read more than a hundred books, the end of the list will get chopped off.&lt;/p&gt;
&lt;p&gt;To solve this issue, we need to do a separate API call for each page of books, fetching only 10 at a time. This means more API calls, but less data that needs to be held in state at any given time. There are just a few minor modifications to be made. In order to get the correct 10 books, we need to add a &lt;code&gt;&amp;amp;page=&lt;/code&gt; parameter to the API call. We pass in the page that we’d like to retrieve. In my case, I just needed to adjust the &lt;code&gt;pageNumber&lt;/code&gt; attribute that I was using previously.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pageNumber: 1,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where this variable was previously set to 0, it now starts out at 1. The WordPress REST API, logically, starts pagination out at page 1.&lt;/p&gt;
&lt;p&gt;The next modification is of the &lt;code&gt;fetchData()&lt;/code&gt; method. Previously, we were only passing the current category along with the request. Now, both the category and the current page number are dynamic variables that we need to pass along. After prepping the variables to reference the current state, we open the API call with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xhr.open(&apos;GET&apos;, apiURL + category + page)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that only the currently visible books are being held in state, pagination has far greater control over how actions are occurring. Hitting either of the pagination buttons should produce a new call to the API. In order to achieve this, we need to watch for changes to the &lt;code&gt;pageNumber&lt;/code&gt; variable, and then fetch new books. This means that we need to make an addition to &lt;code&gt;watch&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;watch: {
  ...
  pageNumber: &apos;fetchData&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, anytime the &lt;code&gt;pageNumber&lt;/code&gt; variable changes, new books will be fetched using the &lt;code&gt;fetchData&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;A small hiccup that I encountered was that I needed to reset &lt;code&gt;pageNumber&lt;/code&gt; to 1 whenever the category was changed. Doing so inside of &lt;code&gt;fetchData&lt;/code&gt; would improperly set the page number, as it would be starting over each time. To solve this, a small modification to the status watcher was required.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;currentStatus: function () {
  this.pageNumber = 1
  this.fetchData()
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of fetching the data right away, adding a function allows for the page number to be reset any time that &lt;code&gt;currentStatus&lt;/code&gt; changes. Afterwards, &lt;code&gt;fetchData()&lt;/code&gt; can be properly called.&lt;/p&gt;
&lt;p&gt;The last piece of this update is with the template. Before, all of the books were contained within state, so getting a count of the total books was pretty easy. Now, we need to check the total number of books with each API call that we make. This data is passed along with the response, so checking it and storing the value in state only requires &lt;code&gt;self.pageCount = xhr.getResponseHeader(&apos;X-WP-TotalPages&apos;)&lt;/code&gt;. Further documentation can be found in the &lt;a href=&quot;https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/&quot;&gt;WordPress REST API Handbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of these changes can be viewed in the larger context of the app by viewing &lt;a href=&quot;https://github.com/samhermes/samhermes.github.io/commit/f3d0fd783e915a0df69c312b9ef8203f1042c663&quot;&gt;the diff on GitHub&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>How not to use React with Jekyll</title><link>https://samhermes.com/posts/how-not-to-use-react-with-jekyll/</link><guid isPermaLink="true">https://samhermes.com/posts/how-not-to-use-react-with-jekyll/</guid><pubDate>Sun, 24 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To lay the groundwork a little, this site uses Jekyll and is hosted on GitHub Pages. Whenever I make a new project that I want to include on the site, I just create a new page in markdown and build out from there. When I made my reading list app, I used Vue and included that without issue. React, on the other hand, has proven to be a little more complex. Which, typical. For this project, I wanted to display information about upcoming SpaceX launches.&lt;/p&gt;
&lt;p&gt;The ever-popular Create React App makes it really easy to get started with React. It can be installed globally with &lt;code&gt;npm install -g create-react-app&lt;/code&gt;. Then, to start this project, I ran &lt;code&gt;create-react-app next-spacex-launch&lt;/code&gt; in the root of my site. This created a new directory and placed a very simple app in it, and then started up a development server. So, with my Jekyll site running, I had the site at &lt;code&gt;localhost:4000&lt;/code&gt; and the React app running at &lt;code&gt;localhost:3000&lt;/code&gt;. Neat, but I wanted React to be running at the subdirectory address. Instead, it was inside of a &lt;code&gt;/build&lt;/code&gt; folder within that subdirectory. So, going to /next-space-launch was a 404.&lt;/p&gt;
&lt;p&gt;At this point, I realized that maybe Create React App isn’t quite the right approach for this project. After doing a little digging, I’ve found that Create React App isn’t really meant for customization. This is fine for most projects, but I needed a little more control. Fortunately, Create React App has the capability to “eject” itself. Essentially, in order to stay simple, it tucks quite a bit of functionality away out of sight. This keeps things tidy, but how am I supposed to experiment like that? There’s a great explanation of the ejection process in the beginning of &lt;a href=&quot;https://medium.com/@tuchk4/why-i-love-create-react-app-e63b1be689a3&quot;&gt;this post on Medium&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, I ejected. &lt;em&gt;gasp!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Reasons I ejected:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I didn’t want the bundle to include a hash. This was making it difficult to include via Jekyll templates. I was able to work around this by renaming the file through &lt;code&gt;package.json&lt;/code&gt;, but that unnecessarily slows the build down a little.&lt;/li&gt;
&lt;li&gt;I kept getting a 404 on the bundle’s .map file, and there was no way to skip that in the build process without deleting the file each time.&lt;/li&gt;
&lt;li&gt;I didn’t want to set up a service worker.&lt;/li&gt;
&lt;li&gt;Most importantly, I wanted to experiment and learn more about the internal mechanisms. That’s reason enough, after all.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After the ejection process is complete, quite a few files are made available in a &lt;code&gt;config&lt;/code&gt; folder. In it, there is a webpack configuration file for both development and production. Through it, I was able to make all of the changes that I listed above.&lt;/p&gt;
&lt;p&gt;Coming at the project from this direction helped give me a jump start. I would have had a lot to figure out if I had started from scratch, and it would have taken much longer to get to a place where I could actually start on the project itself. By ejecting the app after getting my bearings, I was able to get comfortable enough before digging deeper. That being said, Create React App really wasn’t meant to be used within another project. Which, I probably should’ve known. Now I do.&lt;/p&gt;
&lt;p&gt;In the end, I was able to place &lt;code&gt;index.md&lt;/code&gt; inside of the /next-spacex-launch directory, and then point to &lt;code&gt;main.js&lt;/code&gt; inside of the build folder. I am including all of the styles as part of the Jekyll build process, so it’s just the script that is needed. I certainly have more to say about the app itself and how I’m displaying the data, but that’s for another day.&lt;/p&gt;
</content:encoded></item><item><title>I love overscroll-behavior</title><link>https://samhermes.com/posts/i-love-overscroll-behavior/</link><guid isPermaLink="true">https://samhermes.com/posts/i-love-overscroll-behavior/</guid><pubDate>Sun, 10 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Talk about something that you didn’t know you needed! A new CSS property has been proposed (about a year ago by now, actually) called &lt;code&gt;overscroll-behavior&lt;/code&gt; that allows us to limit scrolling to a contained element, without scrolling the entire page as well. This is great for modals, small chat windows, and, in my very specific reason to be excited, mobile menus! There’s a great writeup about it on the &lt;a href=&quot;https://developers.google.com/web/updates/2017/11/overscroll-behavior&quot;&gt;Chrome developer site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Browser support is limited to Chrome (desktop and Android) and Firefox at the moment, according to &lt;a href=&quot;https://caniuse.com/#feat=css-overscroll-behavior&quot;&gt;Can I use&lt;/a&gt;. This means that about 60% of users have it, though, so we’re well on our way to wide support. It appears that IE 11 and Edge support a property called &lt;code&gt;-ms-scroll-chaining&lt;/code&gt;, which works similarly. The only concerning holdout to me is mobile Safari. It would be great to see &lt;code&gt;overscroll-behavior&lt;/code&gt; implemented there. It’s &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=176454&quot;&gt;been reported to the bug tracker&lt;/a&gt; but I’m not sure about future plans.&lt;/p&gt;
&lt;p&gt;What is so great about &lt;code&gt;overscroll-behavior&lt;/code&gt; is that it allows you to limit a users scroll to only the element that they’re currently interacting with. For a mobile menu, this is great. If the menu takes over the entire screen, as many of them do, you can ensure that the user never ends up accidentally scrolling the page behind the menu. If you’ve ever had this happen before, you know how annoying it is. This behavior is known as scroll chaining, and a much better description is available in the &lt;a href=&quot;https://wicg.github.io/overscroll-behavior/#scroll-chaining&quot;&gt;WICG spec for overscroll behavior&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Chrome on Android, by default, when you reach the top of the page, you can pull to refresh the entire page. In this instance, &lt;code&gt;overscroll-behavior&lt;/code&gt; is especially helpful if you’ve implemented your own pull-to-refresh and do not want them to interfere with one another.&lt;/p&gt;
</content:encoded></item><item><title>How to improve the accessibility of tabs</title><link>https://samhermes.com/posts/how-to-improve-accessibility-tabs/</link><guid isPermaLink="true">https://samhermes.com/posts/how-to-improve-accessibility-tabs/</guid><pubDate>Mon, 04 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For quite a few components on the web, there is an accessible way to implement them. For tabs, it’s a little more complicated. With a few attributes, however, we can get pretty close.&lt;/p&gt;
&lt;p&gt;The elements for tabs are very simple. Just an unordered list, links, and &lt;code&gt;divs&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a id=&quot;tab-1&quot; href=&quot;#tab-1&quot;&amp;gt;Tab 1&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a id=&quot;tab-2&quot; href=&quot;#tab-2&quot;&amp;gt;Tab 2&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a id=&quot;tab-3&quot; href=&quot;#tab-3&quot;&amp;gt;Tab 3&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;div id=&quot;tab-1-panel&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div id=&quot;tab-2-panel&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div id=&quot;tab-3-panel&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With added JavaScript to toggle the visibility of the proper &lt;code&gt;div&lt;/code&gt; at the proper time, this is all that’s needed to get tabs working for sighted users. Unfortunately, this is where many stop. However, vast improvements can be made with a few attributes, starting with &lt;code&gt;role&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;For the unordered list and links, there are &lt;code&gt;tablist&lt;/code&gt; and &lt;code&gt;tab&lt;/code&gt; roles. In addition, each list item gets a role of &lt;code&gt;presentation&lt;/code&gt; to remove semantic meaning.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul role=&quot;tablist&quot;&amp;gt;
  &amp;lt;li role=&quot;presentation&quot;&amp;gt;
    &amp;lt;a id=&quot;tab-1&quot; href=&quot;tab-1&quot; role=&quot;tab&quot;&amp;gt;Tab 1&amp;lt;/a&amp;gt;
  &amp;lt;/li&amp;gt;
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For each &lt;code&gt;div&lt;/code&gt;, there is the &lt;code&gt;tabpanel&lt;/code&gt; role.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;tab-1&quot; role=&quot;tabpanel&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, there is a &lt;code&gt;tab&lt;/code&gt; for each &lt;code&gt;tabpanel&lt;/code&gt;, which begins to create a link between two elements that are otherwise unrelated.&lt;/p&gt;
&lt;p&gt;Next, in a similar way, there are &lt;code&gt;aria-*&lt;/code&gt; attributes that need to be added to tabs and tab panels. Going back to the tab list, there is an &lt;code&gt;aria-controls&lt;/code&gt; attribute that points to the &lt;code&gt;id&lt;/code&gt; of its corresponding tab panel.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul role=&quot;tablist&quot;&amp;gt;
  &amp;lt;li role=&quot;presentation&quot;&amp;gt;
    &amp;lt;a id=&quot;tab-1&quot; href=&quot;tab-1&quot; role=&quot;tab&quot; aria-controls=&quot;tab-1-panel&quot;&amp;gt;Tab 1&amp;lt;/a&amp;gt;
  &amp;lt;/li&amp;gt;
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As with &lt;code&gt;tab&lt;/code&gt; and &lt;code&gt;tabpanel&lt;/code&gt;, there is a corresponding attribute that goes with &lt;code&gt;aria-controls&lt;/code&gt;. This is the &lt;code&gt;aria-labelledby&lt;/code&gt; attribute, which needs to be added to each tab panel. The value of the attribute is the &lt;code&gt;id&lt;/code&gt; of the corresponding tab.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;tab-1&quot; role=&quot;tabpanel&quot; aria-labelledby=&quot;tab-1&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, we established the proper identity of all the elements we wish to represent tabs. The last piece of this is to communicate the current state of the tabs. We need to communicate to the user which tab is currently selected, and accordingly, which tab panel is currently visible.&lt;/p&gt;
&lt;p&gt;On each tab, there is &lt;code&gt;aria-selected&lt;/code&gt; that can either be true or false. Using JavaScript, the current tab can be set to &lt;code&gt;true&lt;/code&gt;, and the rest remain &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul role=&quot;tablist&quot;&amp;gt;
  &amp;lt;li role=&quot;presentation&quot;&amp;gt;
    &amp;lt;a id=&quot;tab-1&quot; href=&quot;tab-1&quot; role=&quot;tab&quot; aria-controls=&quot;tab-1-panel&quot; aria-selected=&quot;true&quot;&amp;gt;Tab 1&amp;lt;/a&amp;gt;
  &amp;lt;/li&amp;gt;
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, much like the &lt;code&gt;roles&lt;/code&gt; and other ARIA attributes, there is a corresponding attribute for the tab panels. This one is slightly different, which is confusing at first. Each tab panel needs an &lt;code&gt;aria-hidden&lt;/code&gt; attribute, which is set to &lt;code&gt;true&lt;/code&gt; by default, and &lt;code&gt;false&lt;/code&gt; on the currently active tab. It’s the reverse of the &lt;code&gt;aria-selected&lt;/code&gt; attribute on the tabs, so this tripped me up.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;tab-1&quot; role=&quot;tabpanel&quot; aria-labelledby=&quot;tab-1&quot; aria-hidden=&quot;false&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using JavaScript, these attributes can be updated as the user navigates from tab to tab. The currently selected tab needs to have &lt;code&gt;aria-selected&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;, and the corresponding tab panel needs to have &lt;code&gt;aria-hidden&lt;/code&gt; set to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For these tabs to remain accessible, JavaScript needs to be in working order. Fortunately, without JavaScript, the &lt;code&gt;href&lt;/code&gt; attribute of each tab links directly to the proper tab. The tabs sort of become a table of contents that links down the page. For this reason, it’s good to test the tabs with JavaScript disabled to ensure that users navigating by keyboard still land in the proper place.&lt;/p&gt;
</content:encoded></item><item><title>Closing the gap above sticky elements</title><link>https://samhermes.com/posts/closing-gap-above-sticky-elements/</link><guid isPermaLink="true">https://samhermes.com/posts/closing-gap-above-sticky-elements/</guid><pubDate>Tue, 22 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;position: sticky&lt;/code&gt; is fantastic, and browser support is increasing. However, one little annoyance that keeps happening is that a small gap will appear above an element while it is fixed (as in, it’s stuck to the top of the viewport). At the moment, this is only happening in Chrome, which is convenient, because most everyone uses Chrome.&lt;/p&gt;
&lt;p&gt;This issue is most visible on elements that stick to the top of the viewport while a user scrolls down. If the element has a solid background color, the gap between the element and the top of the viewport allows the content behind the element to be seen scrolling by. This, of course, is only an issue when the element with &lt;code&gt;position: sticky&lt;/code&gt; is currently fixed.&lt;/p&gt;
&lt;p&gt;Fortunately, there’s a fix! This gap comes from the browser calculating the height of preceding elements a little too precisely. For example, say you’ve got a site title with a navigation directly beneath it, and that navigation is sticky. The height of the site title can actually have an effect on the navigation while it’s sticky, as the browser calculates the height of the site title in precise, fractional pixel values. If we set an even pixel height on the site title container, the gap above the sticky navigation will go away.&lt;/p&gt;
</content:encoded></item><item><title>Opening links in a new window</title><link>https://samhermes.com/posts/opening-links-new-window/</link><guid isPermaLink="true">https://samhermes.com/posts/opening-links-new-window/</guid><pubDate>Fri, 18 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the past year, I’ve seen a few people discussing the security dangers of using &lt;code&gt;target=&quot;_blank&quot;&lt;/code&gt; to open links in a new window. The issue is that the page you open in a new window has access to the &lt;code&gt;window&lt;/code&gt; object of the originating page. Seems fairly harmless, but this means the site in the new window could potentially redirect the originating page or perform some other malicious action without permission. Depending on where you’re linking off to, you may not know if the site is secure (especially if it’s loaded with ad trackers).&lt;/p&gt;
&lt;p&gt;The recommendation is to only open links in a new window if you absolutely have to, which is a good practice from a user experience perspective as well. However, if you do open in a new window, ensure that the anchor tag has the following &lt;code&gt;rel&lt;/code&gt; attribute applied any time you use &lt;code&gt;target=&quot;_blank&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;a href=&quot;https://example.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&amp;gt;Example&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Further information about this issue can be found at &lt;a href=&quot;https://jakearchibald.com/2016/performance-benefits-of-rel-noopener/&quot;&gt;Jake Archibald’s site&lt;/a&gt;, where he also goes into detail about the performance benefits (who’d have thought?) of &lt;code&gt;noopener&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Submitting an accessibility-ready theme to WordPress</title><link>https://samhermes.com/posts/submitting-accessibility-ready-theme-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/submitting-accessibility-ready-theme-wordpress/</guid><pubDate>Fri, 11 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This post goes with my talk at WordCamp St. Louis.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;About 2 years ago, I got the idea that I would create and submit my own theme to the official WordPress theme directory. I was curious about the process, and what I could learn from having a theme reviewed.&lt;/p&gt;
&lt;p&gt;I started the theme by forking the &lt;a href=&quot;https://github.com/automattic/_s&quot;&gt;Underscores repository&lt;/a&gt;. I’ve started many projects with Underscores, and it remains a great foundation for getting off the ground quickly. I worked on the theme in my free time for about a year and a half. Finally, this past November, I got to a point where I thought that it was ready to be uploaded.&lt;/p&gt;
&lt;p&gt;In preparation, I ran through the &lt;a href=&quot;https://make.wordpress.org/themes/handbook/review/required/&quot;&gt;list of requirements&lt;/a&gt; on the theme review team page. I ran the &lt;a href=&quot;https://wordpress.org/plugins/theme-check/&quot;&gt;Theme Check&lt;/a&gt; plugin on my site and fixed the errors that it found. With both of those in good shape, I zipped up the theme and went to the &lt;a href=&quot;https://wordpress.org/themes/upload/&quot;&gt;theme upload page&lt;/a&gt;. I very quickly discovered that my preparation had missed one big issue. My theme name was already taken.&lt;/p&gt;
&lt;p&gt;I learned that WordPress looks at all active installations of a theme, so if there is a substantial installation base of a theme, it blocks you from uploading one by the same name. I had only searched for the theme in the WordPress theme directory. Having been rejected, I did a Google search for a WordPress theme by the name of “Harper” and &lt;a href=&quot;https://themeforest.net/item/harper-a-feminine-blog-theme-for-wordpress/15946880&quot;&gt;found one available through ThemeForest&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After this discovery, I wasn’t sure what to do, but eventually gave into finding a new name for the theme. This time, I search the WordPress directory, I did a Google search, and looked for anything that could possibly conflict. I settled on the name “Halle” and went through the theme to make the update, a slightly tedious process. After this, I attempted another upload to the theme directory, and it was accepted.&lt;/p&gt;
&lt;p&gt;Upon successful upload, &lt;a href=&quot;https://themes.trac.wordpress.org/ticket/48322&quot;&gt;a ticket is created for the theme&lt;/a&gt;. This is where the theme review takes place, essentially in a comment thread. After a theme reviewer is assigned (which took about a couple of months in my case), they will provide a list of the changes that need to be made to the theme. Here are some of the most relevant changes I had to make.&lt;/p&gt;
&lt;h2&gt;Accessibility fixes&lt;/h2&gt;
&lt;h3&gt;Color contrast&lt;/h3&gt;
&lt;p&gt;I was a little disappointed to find that I had not checked some of the text colors in my theme for proper contrast. With each post, the entry meta was using a color of #808080, which gives a color contrast of 3.95:1 on a white background. I adjusted these colors to #595959, which has a 7:1 ratio, passing both WCAG AA and AAA. This is easy to test using the &lt;a href=&quot;https://webaim.org/resources/contrastchecker/&quot;&gt;WebAIM Contrast Checker&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Screen reader text&lt;/h3&gt;
&lt;p&gt;In the header of the theme, there is a search icon that opens the search overlay. This icon has no text to accompany it, so it needs something for the screen reader to read out. When I submitted the theme, I was just using the &lt;code&gt;alt&lt;/code&gt; text of the image. This worked, but wasn’t ideal. Instead, I needed to update the &lt;code&gt;alt&lt;/code&gt; attribute to be blank, and then place a &lt;code&gt;span&lt;/code&gt; with the text inside of it immediately following the &lt;code&gt;img&lt;/code&gt; tag. The markup for the span looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;span class=&quot;screen-reader-text&quot;&amp;gt;Search&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Keeping focus inside search modal&lt;/h3&gt;
&lt;p&gt;When the search overlay is open, it covers the entire contents of the page. For a sighted user, we’re locking them into the context of the search field until they close the overlay. We need to duplicate that experience for a user navigating the page by keyboard. In order to do this, we need to make sure that only elements within the search overlay can receive focus while it is open.&lt;/p&gt;
&lt;p&gt;Using a little JavaScript, we gather up any focusable elements (&lt;code&gt;input&lt;/code&gt;, &lt;code&gt;button&lt;/code&gt;, links) and place them in an array. When a user gives focus to any of those elements, we watch for them to reach the last element in the overlay, and then return them to the first element. In the case of my theme, when a user reaches the close button, the next element is the search input field. This means that they are stuck in a loop until the search overlay is closed, which is just what we want.&lt;/p&gt;
&lt;h3&gt;Cross-browser focus states&lt;/h3&gt;
&lt;p&gt;Typically, I will use the browser default for focus states, but this became an issue in Firefox. While Safari and Chrome will show a blue outline around buttons, Firefox shows nothing. From a little bit of testing, I discovered that this was caused by the background and border styles that I was applying to the button. Removing the styles would bring back the browser default focus styles. The fix for this was to manually apply a focus style, which both works in all browsers and looks the same.&lt;/p&gt;
&lt;h3&gt;Focus state on image and text combined link&lt;/h3&gt;
&lt;p&gt;On the homepage of the theme, there is a grouping of three stories that display in a vertical layout. In this case, because the title comes immediately after the image, I wrapped both of them in the same anchor tag. This is better for accessibility, because there is only one link. However, the focus state on those links collapses with the two elements. The fix for this was to apply &lt;code&gt;display: inline-block&lt;/code&gt; to the link.&lt;/p&gt;
&lt;h3&gt;Proper heading structure across posts and pages&lt;/h3&gt;
&lt;p&gt;For the most part, the heading structure in the theme was sound. The only issue was the comment form that can be displayed below both post and page content. The heading “Leave a reply” uses an &lt;code&gt;h3&lt;/code&gt; in Underscores by default. For me, this worked great on posts, where there is a sidebar of the latest posts that uses an &lt;code&gt;h2&lt;/code&gt; for its heading. On pages, the sidebar does not display, which means that the comment form heading needed to be dynamic.&lt;/p&gt;
&lt;p&gt;When setting up the arguments for the comment form, we check to see if we’re currently on a page, and if so, modify the markup for the comment form title.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$comment_args = array();
if ( is_page() ) {
  $comment_args = array(
    &apos;title_reply_before&apos; =&amp;gt; &apos;&amp;lt;h2 id=&quot;reply-title&quot; class=&quot;comment-reply-title&quot;&amp;gt;&apos;,
    &apos;title_reply_after&apos; =&amp;gt; &apos;&amp;lt;/h2&amp;gt;&apos;,
  );
}
comment_form( $comment_args );
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Repetitive link text&lt;/h3&gt;
&lt;p&gt;On any page where there are a whole list of “Read more” links, it can be confusing for a screen reader user to know exactly which “more” is being linked to. Using screen reader text, we can append the title of the post to the end of the link, making each specific to the post that it is associated with. Inside of the link, following the “Read more” text, we add the following markup.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;span class=&quot;screen-reader-text&quot;&amp;gt; &amp;lt;?php get_the_title( get_the_ID() ); ?&amp;gt;&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;General fixes&lt;/h2&gt;
&lt;h3&gt;Making text in JavaScript translatable&lt;/h3&gt;
&lt;p&gt;In my theme, there are only a few places where I’m modifying the text on the page with JavaScript. For comments, there is a toggle to show/hide them, which changes from saying “Show Comments” to “Hide Comments” when the user engages with it. In addition, the mobile menu changes from “Menu” to “Close” when it is toggled. The problem is that text in JavaScript can’t be translated, and so it needs to reside in PHP. &lt;code&gt;wp_localize_script&lt;/code&gt; takes care of this nicely.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wp_localize_script( &apos;halle-scripts&apos;, &apos;halleL10n&apos;, array(
  &apos;menu&apos;  =&amp;gt; esc_html__( &apos;Menu&apos;, &apos;halle&apos; ),
  &apos;close&apos; =&amp;gt; esc_html__( &apos;Close&apos;, &apos;halle&apos; ),
  &apos;comments_show&apos; =&amp;gt; esc_html__( &apos;Show Comments&apos;, &apos;halle&apos; ),
  &apos;comments_hide&apos; =&amp;gt; esc_html__( &apos;Hide Comments&apos;, &apos;halle&apos; ),
) );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, in JavaScript, we just reference &lt;code&gt;halleL10n.menu&lt;/code&gt; to get the “Menu” text, or &lt;code&gt;halleL10n.comments_hide&lt;/code&gt; to get “Hide Comments” and update the page.&lt;/p&gt;
&lt;h3&gt;Only need to support WordPress 3 versions back&lt;/h3&gt;
&lt;p&gt;I was initially check to see if the custom logo function existed before outputting my code, but the custom logo has been part of WordPress since 4.5. With the theme review standards, this means that I did not need to have that check in place. A simple &lt;code&gt;has_custom_logo()&lt;/code&gt; conditional was all that was required.&lt;/p&gt;
&lt;h3&gt;Screenshot image licensing&lt;/h3&gt;
&lt;p&gt;I’m not going to get too deep into licensing, because I don’t understand it all. I was initially using images from Unsplash, and had to swap them out for images that were using the &lt;a href=&quot;https://creativecommons.org/share-your-work/public-domain/cc0/&quot;&gt;CC0 license&lt;/a&gt;. This essentially means that the images needed to be absolutely free with no restrictions at all. I found that there are many images available from &lt;a href=&quot;https://pixabay.com/&quot;&gt;Pixabay&lt;/a&gt; that have the CC0 license, so I was able to use those.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;There’s one last item that I want to mention, and that is a plugin I found out about pretty late in the theme review process. The theme review team has a &lt;a href=&quot;https://github.com/WPTRT/theme-sniffer&quot;&gt;Theme Sniffer plugin&lt;/a&gt; that they use, and it checks your theme for any errors based on the WordPress coding standards. I had only been using the Theme Checker plugin, as it is what is listed in the theme review documentation. I recommend using the sniffer plugin on any project you’re using, it’s gives you a great deal of feedback.&lt;/p&gt;
</content:encoded></item><item><title>Adding pagination in Vue</title><link>https://samhermes.com/posts/adding-pagination-in-vue/</link><guid isPermaLink="true">https://samhermes.com/posts/adding-pagination-in-vue/</guid><pubDate>Thu, 19 Apr 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So, I’ve been reading too much. The reading list that I’ve been maintaining has grown to an unwieldy length (I’m kind of making up problems to solve at this point…). To remedy this, we need pagination!&lt;/p&gt;
&lt;p&gt;Much like when I was adding a loading state, searching Google for help in this project just brought back a lot of packages that I could add to Vue. Not so fetch. A little further down in the results, I found an &lt;a href=&quot;https://medium.com/@denny.headrick/pagination-in-vue-js-4bfce47e573b&quot;&gt;article by Denny Headrick&lt;/a&gt; that laid out a simple implementation. Like the loading state, I didn’t want to load in any superfluous code for something as (supposedly) simple as pagination, plus I wanted to be able to understand a little bit about what was going on.&lt;/p&gt;
&lt;p&gt;The first update was to add a few more items to the &lt;code&gt;data&lt;/code&gt; array. One for the current page number (starting at 0), and another for how many books to display per page. We’ll use these in just a bit.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data: {
  ...
  pageNumber: 0,
  size: 5
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, inside &lt;code&gt;methods&lt;/code&gt;, we need to add two new functions that will take care of updating the &lt;code&gt;pageNumber&lt;/code&gt; value. Since Vue is state based, we just need to update the value of &lt;code&gt;pageNumber&lt;/code&gt; and that will cause the app to update as appropriate. Like, it feels like something is missing, but it just works.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;methods: {
  ...
  nextPage: function() {
    this.pageNumber++;
  },
  prevPage: function() {
    this.pageNumber--;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to add a few functions inside of a new section of the app, computed properties. The first of these functions will give us a count of how many pages in total there are. The second will return a subset of the list of books, depending on which page the user is currently viewing.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;computed: {
  pageCount() {
    let l = this.books.length,
        s = this.size;
    return Math.floor(l/s);
  },

  paginatedData() {
    const start = this.pageNumber * this.size,
          end = start + this.size;
    return this.books.slice(start, end);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I took both of these functions almost verbatim from the article I mentioned above, and then adapted the variable references to work with my app. Thanks Denny!&lt;/p&gt;
&lt;p&gt;One minor change that we need to make to the template before moving on is how we’re looping through the book list. Right now, the current book list is stored in &lt;code&gt;books&lt;/code&gt;, but we want to get it from &lt;code&gt;paginatedData&lt;/code&gt; going forward. It’s as simple as updating the for loop.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template v-for=&quot;book in paginatedData&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final bit is to add the previous and next page button to the template. This is where we can build in the logic to handle what happens when a user presses one of the buttons.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;nav v-if=&quot;pageCount &amp;gt;= 1&quot; class=&quot;book-list-nav&quot;&amp;gt;
  &amp;lt;button type=&quot;button&quot; :disabled=&quot;pageNumber === 0&quot; v-on:click=&quot;prevPage&quot;&amp;gt;Previous&amp;lt;/button&amp;gt;
  &amp;lt;button type=&quot;button&quot; :disabled=&quot;pageNumber &amp;gt;= pageCount&quot; v-on:click=&quot;nextPage&quot;&amp;gt;Next&amp;lt;/button&amp;gt;
&amp;lt;/nav&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s a lot going on here, so let’s break it down a little. On the &lt;code&gt;nav&lt;/code&gt; containing element, we have a conditional statement. This will show/hide the buttons based on how many pages exist. On the reading list, the currently reading list is usually pretty short, so we don’t usually need pagination there.&lt;/p&gt;
&lt;p&gt;For each button, we want to disable them as appropriate if we are on the first or last page. This is where the &lt;code&gt;:disabled&lt;/code&gt; attribute comes in. For the previous button, we check to see if we’re on the first page (page 0), and on the next button, we check for the last page.&lt;/p&gt;
&lt;p&gt;Next up, we hook up the functions that we added to &lt;code&gt;methods&lt;/code&gt; earlier. To attach a click handler, we use &lt;code&gt;v-on:click&lt;/code&gt;, and then insert the name of the function we want to use as the value.&lt;/p&gt;
&lt;p&gt;And that’s it! So simple! So easy! Just kidding, this is pretty complicated. JavaScript is tricky. Once I figured this out, though, it feels pretty nice. The logic to show/hide the navigation as appropriate is pretty simple to follow, and all we had to do was add an attribute to the &lt;code&gt;nav&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;To take this a little further, I’d like to add a way to communicate the current page. Ideally, there would be “1 of 4” between the previous and next buttons. Also, I’ve limited the list to 5 books, so that usually fits within the current viewport. If I were to extend that to 10 books, we’d really want to scroll the user back up to the top of the list any time they used the pagination. Always more to do!&lt;/p&gt;
</content:encoded></item><item><title>Lazy loading images</title><link>https://samhermes.com/posts/lazy-loading-images/</link><guid isPermaLink="true">https://samhermes.com/posts/lazy-loading-images/</guid><pubDate>Wed, 21 Mar 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;First things first, we needn’t write a lazy loading script ourselves. There are so many options out there. For many people, having a non-javascript fallback isn’t too much of a concern. But, I am not most people. This led me to lazyload.js, which just so happens to be the first result on Google for “lazy load script”. Maybe I am most people.&lt;/p&gt;
&lt;p&gt;So, we include lazyload.js in the footer of the page, and then we call &lt;code&gt;lazyload();&lt;/code&gt;. I’ve modified my copy of the lazyload.js script to include this in the bottom of the file, so that it gets called right after it loads, but it could also be called in the footer of the page like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script src=&quot;lazyload.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;lazyload();&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to adjust the image markup we’re using. We apply a class of &lt;code&gt;lazyload&lt;/code&gt; to each &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, and move the URL of the image file from the &lt;code&gt;src&lt;/code&gt; attribute to a new attribute called &lt;code&gt;data-src&lt;/code&gt;. It will now look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;img class=&quot;lazyload&quot; data-src=&quot;banana-tree.jpg&quot; alt=&quot;A banana tree.&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By moving the image source from the &lt;code&gt;src&lt;/code&gt; attribute to a &lt;code&gt;data-&lt;/code&gt; attribute, we prevent the browser from downloading the image file, and then the lazy load script will move the image URL from the &lt;code&gt;data-&lt;/code&gt; attribute to the &lt;code&gt;src&lt;/code&gt; attribute, triggering a download.&lt;/p&gt;
&lt;p&gt;We really only want to set this up for images that are, pardon my language, but, below the fold. Images that are seen by the user as the page loads should not use a lazy loading technique, as the browser default works just fine! For my photo page, I started applying the lazy loading technique on the third image.&lt;/p&gt;
&lt;p&gt;Now that we’ve got images lazy loading, what do we do when JavaScript isn’t working or enabled? Right now, none of the lazy load images will load, and we’ll just have some confused users. This is assuming that anyone looks at my photo page, but still. We just need to add an additional image tag, and wrap it in a &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; tag. Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;noscript&amp;gt;
  &amp;lt;img src=&quot;walnut-tree.jpg&quot; alt=&quot;A walnut tree.&quot;&amp;gt;
&amp;lt;/noscript&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we’ve got now is a fairly bare-bones lazy loading setup, but it works quite well. If I were to add a hundred photos to the page, only the first two would load by default, and the user would only download the photos that they scrolled down to. This is a fantastic relief for anyone who is on a data plan, especially if they land on the page without knowing what they are about to do. Small improvements like lazy loading can have a huge impact.&lt;/p&gt;
</content:encoded></item><item><title>Adding a loading state to Reading List</title><link>https://samhermes.com/posts/adding-loading-state-reading-list/</link><guid isPermaLink="true">https://samhermes.com/posts/adding-loading-state-reading-list/</guid><pubDate>Tue, 27 Feb 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a continuation of my &lt;a href=&quot;https://samhermes.com/posts/small-vue-app-reading-list/&quot;&gt;previous post about a Vue app&lt;/a&gt; I created for the reading list on this site.&lt;/p&gt;
&lt;p&gt;After I got the books displaying, the first thing I felt was missing was a loading state. It takes a second (or more, depending on connection speed) for the books to load in, and in the meantime, there’s just a white screen. Even on this super simple app, that’s not a great experience.&lt;/p&gt;
&lt;p&gt;Naturally, I went looking for information. I found quite a few collections of loading spinners, which seems like overkill. I mean, I made a list of books into a Vue app, so everything is overkill, but it just seems crazy to add this whole collection of spinners just to use one of them. Plus, I wanted to make my own spinner, that’s the fun part.&lt;/p&gt;
&lt;p&gt;What we need is for Vue to communicate out when it’s fetching data, and when it’s not. Once we have that information, we can toggle the display of the loading spinner. So, let’s do a little state management. We start by setting the default loading state to &lt;code&gt;false&lt;/code&gt; in the initial data set.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data: {
  statuses: [
    { id: 1, title: &apos;Currently&apos; },
    { id: 2, title: &apos;Completed&apos; }
  ],
  currentStatus: &apos;1&apos;,
  books: null,
  loading: false
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vue doesn’t fetch data right away, even though it can seem that way, so we don’t want the loading state to be true until Vue has actually reached out to request data. We set the initial state to &lt;code&gt;false&lt;/code&gt;, and later update that value as soon as a request has been started.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;methods: {
  fetchData: function() {
    this.loading = true
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that &lt;code&gt;fetchData&lt;/code&gt; has started, the loading value is set to &lt;code&gt;true&lt;/code&gt;. Now, the last piece to complete this is to set the loading value back to &lt;code&gt;false&lt;/code&gt; once we get some data back from our request. This comes inside the &lt;code&gt;onload&lt;/code&gt; function. Continuing on from above:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xhr.onload = function() {
  this.loading = false
  self.books = JSON.parse(xhr.responseText)
}.bind(this)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One bit to note about the code above is that we need to add &lt;code&gt;.bind(this)&lt;/code&gt; to the end of the &lt;code&gt;onload&lt;/code&gt; function. Pardon me if I don’t get this exactly right, but doing this allows us to access and update the value of &lt;code&gt;loading&lt;/code&gt; outside the current function. Otherwise, &lt;code&gt;this.loading&lt;/code&gt; is undefined, and we would never be able to communicate that loading has finished.&lt;/p&gt;
&lt;p&gt;The full &lt;code&gt;reading-list.js&lt;/code&gt; is &lt;a href=&quot;https://github.com/samhermes/samhermes.github.io/blob/master/js/reading-list.js&quot;&gt;available on GitHub&lt;/a&gt; for a full picture of this implementation.&lt;/p&gt;
&lt;p&gt;Now, we have a little work to do in our template and styles. We need to add the loading animation to our template and control its display using the &lt;code&gt;loading&lt;/code&gt; variable. Here, I have added a &lt;code&gt;div&lt;/code&gt; with a class of &lt;code&gt;loading&lt;/code&gt;, and used &lt;code&gt;v-show&lt;/code&gt; to toggle an inline style attribute. &lt;code&gt;loading&lt;/code&gt;, when used inside of &lt;code&gt;v-show&lt;/code&gt; is a reference to the variable we’ve been working with.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;loading&quot; v-show=&quot;loading&quot;&amp;gt;
  {% raw %}{% include loading.svg %}{% endraw %}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I won’t get into the SVG I used except to say that I’ve added it to my &lt;code&gt;_includes&lt;/code&gt; folder. My site is in Jekyll, so that’s where it is looking for when &lt;code&gt;include&lt;/code&gt; is used.&lt;/p&gt;
&lt;p&gt;I also won’t get into the styles I used for the loading spinner, because that will depend on specific cases. Essentially, I’ve absolutely positioned mine so that it will display centered over the content area where the book list will show. One bit that I will touch on is the animation of the spinner. We can use a pretty simple CSS animation to keep the spinner spinning indefinitely. We first set up the keyframe animation, and here I’ve given it the very accurate name of &lt;code&gt;rotate&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, on the styles for SVG itself, we can add on &lt;code&gt;animation: rotate 1.8s linear infinite;&lt;/code&gt;, and we’re all set. Now, it will smoothly rotate.&lt;/p&gt;
&lt;p&gt;With a loading state, the user will always know what is happening with our application. On the reading list, when someone toggles between books I am currently reading and books I’ve completed, they know exactly when data has been requested, and when it has arrived. Or, hasn’t arrived. It’s a small UX improvement that goes a long way.&lt;/p&gt;
</content:encoded></item><item><title>A small Vue app - Reading List</title><link>https://samhermes.com/posts/small-vue-app-reading-list/</link><guid isPermaLink="true">https://samhermes.com/posts/small-vue-app-reading-list/</guid><pubDate>Wed, 24 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Getting into new JavaScript is difficult when you don’t have something useful to build with it, so I was excited when I put it together that I could add Vue to my existing reading list. I’ve had it as static content for a little while now. Making updates is manual, and ends up with lots of repeated code. So, my idea was to move the listings to a WordPress install, and then bring them into the page and display them using Vue. Here’s how I did that.&lt;/p&gt;
&lt;h2&gt;Starting somewhere&lt;/h2&gt;
&lt;p&gt;It’s always good to have somewhere to start, and I got over the initial hump by looking over Brian Krogsgard’s example Vue project on CodePen. He’s pulling in posts from Post Status and displaying them on the page. Fairly simple, but it also includes a toggle to switch between authors. This translated well to the distinction on my reading list between books I’ve completed and ones I’m currently reading. I was pretty excited to see that the amount of code to get going was minimal.&lt;/p&gt;
&lt;h2&gt;Prepping WordPress&lt;/h2&gt;
&lt;p&gt;I have a WordPress environment that runs on samhermes.co, and so I fired up a new site there. It is just using a default theme, since all I need to use is a REST API endpoint. I wonder what you’d do if all you wanted was the endpoints from your site? Could you remove everything else from public view? These are questions for another day. After I had loaded in the books, I added them to two categories, one for current and one for completed. Then, I wanted to add the author of each book, so I activated ACF and created a field called “Author” and loaded in the data.&lt;/p&gt;
&lt;p&gt;Before the REST API endpoint is totally ready to go, the custom field needs to be added. By default, anything you add with ACF isn’t going to show up in the response. The following function will add all fields to the response.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function acf_rest_api() {
  register_rest_field( &apos;post&apos;,
    &apos;fields&apos;,
    array(
      &apos;get_callback&apos; =&amp;gt; function( $data, $field, $request, $type ) {
        if ( function_exists( &apos;get_fields&apos; ) ) {
          return get_fields( $data[&apos;id&apos;] );
        }
        return [];
      },
      &apos;update_callback&apos; =&amp;gt; null,
      &apos;schema&apos; =&amp;gt; null,
    )
  );
}
add_action( &apos;rest_api_init&apos;, &apos;acf_rest_api&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I was surprised to find that I didn’t have to add each field individually. I found a method that this could be done, but in my case it was easiest to just have all fields added, which will be especially helpful if I choose to add additional information in the future.&lt;/p&gt;
&lt;h2&gt;Setting up Vue&lt;/h2&gt;
&lt;p&gt;After adding the minified version of Vue to the page, the next step is to create a Vue instance. The entirety of this piece is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var apiURL = &apos;https://samhermes.co/reading-list/wp-json/wp/v2/posts?categories=&apos;

var books = new Vue({
  el: &apos;#app&apos;,
  data: {
    statuses: [
      { id: 1, title: &apos;Currently&apos; },
      { id: 2, title: &apos;Completed&apos; }
    ],
    currentStatus: &apos;1&apos;,
    books: null
  },
  created: function() {
    this.fetchData()
  },
  watch: {
    currentStatus: &apos;fetchData&apos;
  },
  methods: {
    fetchData: function() {
      var xhr = new XMLHttpRequest()
      var self = this
      xhr.open(&apos;GET&apos;, apiURL + self.currentStatus)
      xhr.onload = function() {
        self.books = JSON.parse(xhr.responseText)
      }
      xhr.send()
    }
  }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first part we see here is the URL for the API. You’ll see that it ends sort of abruptly, allowing us to tack on an ID as we make the request. The default ID is 1, which matches the ID of the “Currently” category in WordPress. We set that as the default, so that as the page loads, it uses it for the initial request. When the user changes the current status (either “Currently” or “Completed”), we send the new ID along with the new request.&lt;/p&gt;
&lt;p&gt;The methods section contains a function to fetch new data, and it is a fairly simple Ajax request. Vue watches for a change in &lt;code&gt;currentStatus&lt;/code&gt; and performs a &lt;code&gt;fetchData&lt;/code&gt; when it does.&lt;/p&gt;
&lt;h2&gt;Page Markup&lt;/h2&gt;
&lt;p&gt;Vue needs a container to target, and it needs to match the ID in the &lt;code&gt;el&lt;/code&gt; attribute that we’ve already created. It’s just a simple &lt;code&gt;&amp;lt;div id=&quot;app&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; that we’ll place all of the following code inside of.&lt;/p&gt;
&lt;p&gt;This next part is what I’ve been poking around on still. The template that Vue uses to actually create the markup on the page can live in a couple of different places. Currently, I have it inside a couple of &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; tags on the page itself.&lt;/p&gt;
&lt;p&gt;First, you can use a for loop in Vue to create a list of the possible statuses. For my example, I wanted two radio buttons that are labeled as “Currently” and “Completed.”&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template v-for=&quot;status in statuses&quot;&amp;gt;
  &amp;lt;input type=&quot;radio&quot;
  :id=&quot;status.id&quot;
  :value=&quot;status.id&quot;
  :name=&quot;status.id&quot;
  v-model=&quot;currentStatus&quot;&amp;gt;
  &amp;lt;label :for=&quot;status.id&quot; v-html=&quot;status.title&quot;&amp;gt;&amp;lt;/label&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s a little weird to be writing a for loop using markup, but it feels sort of familiar and it was pretty easy to understand what was going on. In this example, we just get a list of two radio buttons with corresponding labels. Here, attributes that have a “:” before them are dynamic, and they pull their value from the current &lt;code&gt;status&lt;/code&gt; object. The attributes that have “v-” before them aren’t exactly dynamic, but they’re more like instructions for Vue. &lt;code&gt;v-model&lt;/code&gt; hooks the inputs into Vue and gives them their interactivity. It communicates the current value of &lt;code&gt;currentStatus&lt;/code&gt; to the Vue instance. &lt;code&gt;v-html&lt;/code&gt; takes the status title and outputs it as text inside the label element.&lt;/p&gt;
&lt;p&gt;As for the markup for the actual book list, it’s a fairly simple setup, and even easier to understand than the radio button markup. We wrap it in an unordered list tag and then create a for loop to iterate over each of the books, listing the title and author for each.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul class=&quot;book-list&quot;&amp;gt;
&amp;lt;template v-for=&quot;book in books&quot;&amp;gt;
  &amp;lt;li&amp;gt;
    &amp;lt;p class=&quot;book-title&quot; v-html=&quot;book.title.rendered&quot;&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;p class=&quot;author&quot; v-html=&quot;book.fields.author&quot;&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;/li&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this part, we’re referencing the author field that we added to the WP REST API by looking for the &lt;code&gt;fields&lt;/code&gt; attribute of the current book. The field we created, named “author,” is available to us there.&lt;/p&gt;
&lt;h2&gt;Performance Concerns&lt;/h2&gt;
&lt;p&gt;Using Vue is absolutely overkill for displaying a list of books. This specific project was definitely just a proof-of-concept so that I could dig into Vue. The Vue file minified is 90k on the server. My site uses CloudFlare, so I’m benefiting from their compression (I think, it&apos;s magic), which gets it down to 30k when loaded in the browser. Not terrible by any means, but it was 0k of JavaScript when it was just a static list.&lt;/p&gt;
&lt;p&gt;Aside from loading Vue, there’s also the small performance enhancement we could make of caching the responses. Since my reading list is fairly static, we could cache the response locally and just look for it in cache instead of going back out to the API. As it currently stands, toggling the current status back and forth results in a bunch of needless requests.&lt;/p&gt;
</content:encoded></item><item><title>CSS skills should be valued as much as JavaScript skills</title><link>https://samhermes.com/posts/but-what-about-css-skills/</link><guid isPermaLink="true">https://samhermes.com/posts/but-what-about-css-skills/</guid><pubDate>Wed, 20 Dec 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Honestly, this should have just been a tweet, because it’s as simple as that. However, I deleted my account so we’re just going to have to give it deeper consideration.&lt;/p&gt;
&lt;h2&gt;Why do I feel this way?&lt;/h2&gt;
&lt;p&gt;A few months ago there were discussions about the job title “front end developer” and exactly what responsibilities fall under that domain. From the developers viewpoint, what should they be studying up on? From a hiring manager’s viewpoint, what skills should they be asking for, expecting, interviewing on, etc.? Looking at a sampling of job postings, it seems to be that front end developers need to know JavaScript, and maybe CSS gets listed next to HTML. You should know React, Angular, Vue (that all three of those would ever end up in the same listing is concerning), and then everything else is pretty much secondary.&lt;/p&gt;
&lt;p&gt;Who is responsible for the styles then? Who is going to ensure that your interfaces don’t fall apart the moment you add new functionality? Who is even keeping track of patterns, components, shared standards? Apparently a front end developer spends something like 2% of their time on these things?&lt;/p&gt;
&lt;h2&gt;Why is this important?&lt;/h2&gt;
&lt;p&gt;Performance, accessibility, maintainability, user experience… I could go on.&lt;/p&gt;
&lt;p&gt;If you know CSS really well, you know how to ship performative CSS. You know how to ship less CSS. You know how to ship accessible CSS. And these are two incredibly important aspects of any web project. As the web continues to reach people it never has before, performance and accessibility just get more important.&lt;/p&gt;
&lt;p&gt;Additionally, as more and more CSS is added to a project, the harder it is to keep track of it all. Creating style guides, pattern libraries, and component systems are all important tasks for the longevity of a project. The developers who create a project may not maintain it in 2 years, and someone with strong CSS skills is writing code with an eye to the future.&lt;/p&gt;
&lt;h2&gt;What do we do?&lt;/h2&gt;
&lt;p&gt;A little while ago, I switched my title on my website to “UI Developer,” as it seems to better describe my skills, abilities, and talent. I don’t think that “front end developer” accurately describes my role anymore, even though my day to day work hasn’t changed that much. So, part of the solution is for developers who love this part of the stack to own it.&lt;/p&gt;
&lt;p&gt;Beyond titles, we need to adjust how we talk about CSS skills. Unlike JavaScript, it can be hard to define what “good” CSS is. It’s a little more subjective. Writing or talking about CSS can involve more gray area, which is harder to talk about than a straightforward snippet of code. However, we need to be having these conversations. Discussions should happen around how UI elements work within a larger system, and how to make exceptions. We need to talk about browser support and what can cause accessibility issues. Also, beyond a chosen methodology, we have to think about how we get everyone on the same page with how we create UI within our organizations.&lt;/p&gt;
&lt;p&gt;As much as I’m feeling this issue of giving CSS priority, my own site is having trouble. It can be difficult to write and share CSS outside of a larger system, and the posts are slightly more difficult to write. It’s been a concern of mine for a while now that my writing doesn’t align well with what I am most interested in. This is definitely something I need to course correct on. Walk the talk!&lt;/p&gt;
</content:encoded></item><item><title>Getting started with CSS grid</title><link>https://samhermes.com/posts/getting-started-with-css-grid/</link><guid isPermaLink="true">https://samhermes.com/posts/getting-started-with-css-grid/</guid><pubDate>Mon, 06 Nov 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CSS grid has been out in the wild for a little while now, and though I still have a little hesitation about putting it into production, it’s worth studying up on it. For all of the complexity that CSS grid brings, it’s incredibly simple to get started. Many of the basic layout tasks that I’ve attempted so far have only required a few properties to be specified on the parent element. Let’s look at a run-of-the-mill example.&lt;/p&gt;
&lt;h2&gt;Two Column Layout&lt;/h2&gt;
&lt;p&gt;One of the most common layouts, this used to require a pairing of floats and widths. Although &lt;code&gt;calc()&lt;/code&gt; introduced new possibilities for how widths could be calculated, it still wasn’t powerful (or easy) enough.&lt;/p&gt;
&lt;p&gt;We begin by enabling grid on the parent element with a new value for the display property.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.two-column {
  display: grid;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From there, we need to decide the widths for each column. For a sidebar, we could set up a fixed or flexible width for it. Here, we give it a fixed width of &lt;code&gt;15em&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.two-column {
  display: grid;
  grid-template-columns: 15em 1fr;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you probably noticed, we’ve got a new measurement in use here. CSS grid adds the &lt;code&gt;fr&lt;/code&gt; unit, or fraction unit. It’s incredibly powerful, and here, using &lt;code&gt;1fr&lt;/code&gt;, it fills up the remaining space.&lt;/p&gt;
&lt;p&gt;We can use the fraction unit to develop our own grid system of sorts, and the possibilities are unlimited. To create a percentage-based layout similar to what we’ve already done, we use two values in fractions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.two-column {
  display: grid;
  grid-template-columns: 10fr 4fr;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we’re on a fairly large screen, this layout probably looks great. However, we probably only want to apply it when the screen is wider than &lt;code&gt;600px&lt;/code&gt;, or &lt;code&gt;37.5em&lt;/code&gt;, or so.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media screen and (min-width: 37.5em) {
  .two-column {
    display: grid;
    grid-template-columns: 15em 1fr;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This feels really familiar, and goes along with what we’ve been doing with flexbox. Using grid with media queries, we only apply the layout changes when we’d like them to take effect.&lt;/p&gt;
&lt;p&gt;The last piece of this layout is the most exciting. Whereas we needed to perform quite a bit of management of the margin between elements with float layouts, this is no longer an issue. Grid gap takes care of this in a clean, simple way. Floats required adding margin to both sides, or removing it from the last child. Grid gap just gets to the point.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.two-column {
  display: grid;
  grid-template-columns: 15em 1fr;
  grid-gap: 5em;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we’re telling grid to set the first column to &lt;code&gt;15em&lt;/code&gt;, then add a blank &lt;code&gt;5em&lt;/code&gt; gap, and then fill up the remaining space with the second element. A flexible or fixed value could be used here, just like with our column measurements.&lt;/p&gt;
&lt;p&gt;It’s incredibly exciting to have such a powerful layout engine baked into browsers, and I can’t wait to use these properties in production. With the appropriate fallbacks, those who wish to live on the edge can use CSS grid in production today. I’ll be writing about how that can be done next.&lt;/p&gt;
</content:encoded></item><item><title>Buttons need a declared type</title><link>https://samhermes.com/posts/buttons-need-declared-type/</link><guid isPermaLink="true">https://samhermes.com/posts/buttons-need-declared-type/</guid><pubDate>Thu, 26 Oct 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When using a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element, the default type is &lt;code&gt;submit&lt;/code&gt;. So, if you’re just going for a toggle button or other interactive functionality, &lt;code&gt;type=&quot;button&quot;&lt;/code&gt; should be added.&lt;/p&gt;
&lt;p&gt;I was reading through &lt;a href=&quot;https://css-tricks.com/random-interesting-facts-htmlsvg-usage/#article-header-id-12&quot;&gt;an article in CSS Tricks&lt;/a&gt; from last November about HTML/SVG usage, and it notes that in their study of sites in the wild, about 30% of buttons did not have any attribute at all. Hate to admit, I think I&apos;ve contributed to that figure.&lt;/p&gt;
&lt;p&gt;Of additional interest, buttons do not need &lt;code&gt;role=&quot;button&quot;&lt;/code&gt; as it is implied. This is according to the &lt;a href=&quot;https://w3c.github.io/html/sec-forms.html#the-button-element&quot;&gt;HTML specification on buttons&lt;/a&gt;, where it notes that ARIA roles that match the implicit role of the element are not recommended. Further reading about this can be found at &lt;a href=&quot;https://w3c.github.io/html/dom.html#aria-authoring-requirements&quot;&gt;w3c.github.io/html/dom.html&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Append theme version to stylesheet</title><link>https://samhermes.com/posts/append-theme-version-to-stylesheet/</link><guid isPermaLink="true">https://samhermes.com/posts/append-theme-version-to-stylesheet/</guid><pubDate>Mon, 25 Sep 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;With browsers getting more aggressive about holding on to local cache, it can be aggravating to hear that an end user doesn’t see updates, or they see something quite broken because a few styles are missing. This can be improved by appending a version number to the end of any stylesheet in your project.&lt;/p&gt;
&lt;p&gt;In WordPress, the version number can come straight from the theme. To get the theme’s current version, make a call to &lt;code&gt;wp_get_theme()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$theme_version = wp_get_theme()-&amp;gt;get( &apos;Version&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returns the theme’s current version and stores it in a variable. To use the &lt;code&gt;$theme_version&lt;/code&gt; variable when enqueuing styles, add it like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wp_enqueue_style( &apos;theme-style&apos;, get_stylesheet_uri(), array(), $theme_version );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, for this to be effective, you’ll want to bump your theme’s version any time you have a new release. Now, whether you’re developing or publicly releasing a new feature, you can rest easier knowing that your end users are seeing what you’re seeing.&lt;/p&gt;
</content:encoded></item><item><title>Explaining accessible modals</title><link>https://samhermes.com/posts/explaining-accessible-modals/</link><guid isPermaLink="true">https://samhermes.com/posts/explaining-accessible-modals/</guid><pubDate>Fri, 18 Aug 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Accessibility on the web is tricky, and modals are even trickier. Fortunately, there seem to be quite a few resources for getting there, one being &lt;a href=&quot;https://frend.co&quot;&gt;Frend&lt;/a&gt;. It includes a component for an accessible modal that provides a small JavaScript library that hooks up to a modal and takes care of the rest. Only problem is that it’s a little too component-ized to understand what’s going on under the hood. The documentation says that you can just call &lt;code&gt;var myModal = Frdialogmodal();&lt;/code&gt; and you’re good to go. But what’s really happening, and how might we adapt it for our own use?&lt;/p&gt;
&lt;p&gt;Before I dig into this, I think it’s worth pointing out that “modal” is sort of a loose definition of what this will work for. In my current project, it’s less of a modal and more of a change of focus. In the Frend component, the main work that the JavaScript is doing is keeping the focus within the modal content while it is open and then putting the focus back where it was when the modal is closed. Someone who is tabbing through the site should be able to enter the context of the modal and then get back out of it when they’re ready. This works for modals or any event where you might be shifting context based on user input.&lt;/p&gt;
&lt;h2&gt;Event binding&lt;/h2&gt;
&lt;p&gt;First things first, the display of a modal has to be triggered by an action taken by the user. Likely, that’s a click on a button. When a click event occurs, we want to attach an event listener that will listen for &lt;code&gt;keydown&lt;/code&gt; events like so: &lt;code&gt;document.addEventListener(&apos;keydown&apos;, modalTab);&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Collecting all focusable elements&lt;/h2&gt;
&lt;p&gt;Next up, if we’re going to be using the tab key, we need to find all of the elements that we want to be tabbed through. Essentially, we want to begin restricting focus states to a select group of elements that are inside the modal, and then loop through them as if the modal were a miniature webpage.&lt;/p&gt;
&lt;p&gt;We’re going to pass an array of all possible types of focusable elements into a function that will perform a &lt;code&gt;querySelectorAll()&lt;/code&gt; within the context of the modal. Then we’ll end up with all of the elements to be tabbed through.&lt;/p&gt;
&lt;p&gt;Here’s an array containing all possible focusable elements:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var focusableSelectors = [&apos;a[href]&apos;, &apos;area[href]&apos;, &apos;input:not([disabled])&apos;, &apos;select:not([disabled])&apos;, &apos;textarea:not([disabled])&apos;, &apos;button:not([disabled])&apos;, &apos;iframe&apos;, &apos;object&apos;, &apos;embed&apos;, &apos;[contenteditable]&apos;, &apos;[tabindex]:not([tabindex^=&quot;-&quot;])&apos;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those are some pretty tricky selectors! For the most part, this will take care of just about anything you’d put in a modal, but you’ll want to make sure that this list matches up with reality.&lt;/p&gt;
&lt;p&gt;Once we know what types of elements could be focusable, we need to look inside of the modal content and gather up any element that matches. We can do that with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var modal = document.querySelector(&apos;.modal&apos;);
var focusableElements = function() {
  return [].slice.call( modal.querySelectorAll( focusableSelectors.join() ) );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this function, if there are two anchor tags and a close button in the modal, an array with the two anchor links and button will be returned. This function will be used in the next step anytime the tab key is pressed.&lt;/p&gt;
&lt;h2&gt;Handling tab keydown&lt;/h2&gt;
&lt;p&gt;Now that the event listener is waiting for &lt;code&gt;keydown&lt;/code&gt; events and we&apos;ve got a list of all focusable elements, we can check to see if the user is using the tab key. This will be done within the &lt;code&gt;modalTab()&lt;/code&gt; function, so let’s get that started.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function modalTab(event) {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s important to pass the &lt;code&gt;event&lt;/code&gt; in to the function so that we can capture which key is being used. Our first check will be just that, through the following check:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (event.keyCode === 9) {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The magic key code for the tab key is &lt;code&gt;9&lt;/code&gt;. When I first learned that keys were mapped to numbers, it seemed like something that could fall apart pretty easily, but it holds up! Tech!&lt;/p&gt;
&lt;h2&gt;Creating a focus loop&lt;/h2&gt;
&lt;p&gt;We now move into controlling what happens when the first or last element is tabbed past. We want to drop the user’s focus state back on the first element if they get to the end of the modal and hit tab, and this should work in the inverse as well.&lt;/p&gt;
&lt;p&gt;The following code is still inside the &lt;code&gt;modalTab()&lt;/code&gt; function, and inside the conditional tag we created above that’s checking to make sure the &lt;code&gt;keyCode&lt;/code&gt; is &lt;code&gt;9&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Get the index of the currently focused element within the modal
var focusedIndex = focusableElements.indexOf(document.activeElement);

// If the shift key is not in use, check to see if we&apos;re on the last element
if (!e.shiftKey &amp;amp;&amp;amp; focusedIndex === focusableElements.length - 1) {
  // Focus first item within modal
  focusableElements[0].focus();
  e.preventDefault();
// If the shift key is in use, we&apos;re going backwards, so check to see if we&apos;re on the first element
} else if (e.shiftKey &amp;amp;&amp;amp; (focusedIndex === 0 || focusedIndex === -1)) {
  // Focus last item within modal
  focusableElements[focusableElements.length - 1].focus();
  e.preventDefault();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We really don’t need to know what’s happening on the elements between the first and last element of the modal, their focus state can remain untouched by our script. We’re just waiting for the first or last.&lt;/p&gt;
&lt;h2&gt;Removing event listener on close&lt;/h2&gt;
&lt;p&gt;We really only want to listen for keydown events while the modal is open, so we’ll want to remove this event listener when the modal is closed. Since this could unexpectedly cause issues with other elements on the page, it’s safest to restrict our functions to just the modal. We’d remove the event listener like so: &lt;code&gt;document.removeEventListener(&apos;keydown&apos;, modalTab);&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Additional considerations&lt;/h2&gt;
&lt;p&gt;Beyond handling the focus state, we’ll also want to manage state on a few other items. By default, the container of the modal should receive &lt;code&gt;role=&quot;dialog&quot;&lt;/code&gt; as well as &lt;code&gt;aria-hidden=&quot;true&quot;&lt;/code&gt;. When the modal is opened, the &lt;code&gt;aria-hidden&lt;/code&gt; attribute should be updated to &lt;code&gt;false&lt;/code&gt;, and then set back to &lt;code&gt;true&lt;/code&gt;  on close. This could be done with the following: &lt;code&gt;modal.setAttribute(&apos;aria-hidden&apos;, true);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will vary based on what content is contained within the modal, but the first element should receive focus when the modal is opened. Whether this is just the first anchor tag or the modal container itself, the focus should be added to get the user started off properly.&lt;/p&gt;
&lt;p&gt;To learn more about how this works, the JS file for the Frend modal component is a great place to start. Much of what I went over in this post is contained within. &lt;a href=&quot;https://github.com/frend/frend.co/blob/gh-pages/_components/dialogmodal/dialogmodal.js&quot;&gt;View it on Github&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Omitting optional HTML tags</title><link>https://samhermes.com/posts/omitting-optional-html-tags/</link><guid isPermaLink="true">https://samhermes.com/posts/omitting-optional-html-tags/</guid><pubDate>Mon, 24 Jul 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Someone mentioned somewhere at some point (life moves too fast) that the &lt;a href=&quot;https://google.github.io/styleguide/htmlcssguide.html#Optional_Tags&quot;&gt;Google HTML/CSS Style Guide&lt;/a&gt; suggests that any unnecessary HTML tags can be omitted, such as the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. This was rather interesting to me, and so quintessential of the web. Even the things you think are so foundational may not be.&lt;/p&gt;
&lt;p&gt;I updated my Jekyll layout to remove optional tags, which means the page you’re currently viewing does not have a &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag or a &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag. The page source goes from the document type declaration right to a meta tag. The RSS link is followed immediately by the &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;p&gt;Of course, Google isn’t suggesting something new here, they’re simply following the HTML standard. The standard allows for the omission of quite a few other tags, such as the closing tag for &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, among others. There are some conditionals around when this will work, though in most cases it seems feasible. Always good to &lt;a href=&quot;https://html.spec.whatwg.org/multipage/syntax.html#syntax-tag-omission&quot;&gt;check the spec&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since I’m using Jekyll to generate my site, I don’t have total control over the markup generated within the content of the site, but omitting a simple &lt;code&gt;&amp;lt;/li&amp;gt;&lt;/code&gt; is neither here nor there. Still, interesting to consider that you can ship HTML without some of the most foundational tags.&lt;/p&gt;
</content:encoded></item><item><title>Unregistering widgets in WordPress</title><link>https://samhermes.com/posts/unregistering-widgets-in-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/unregistering-widgets-in-wordpress/</guid><pubDate>Sat, 03 Jun 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’ve ever installed Jetpack, you’re probably familiar with widget overload. Sometimes it’s better to cut down on the number of widgets available to your users, both for the benefit of their cognitive load and just for the fact that they may never use some of them. Meta widget, anyone?&lt;/p&gt;
&lt;p&gt;Unregistering a widget is a fairly small bit of code, but getting all of the information you need can sometimes be the tricky part.&lt;/p&gt;
&lt;p&gt;Here is a function that hooks into the &lt;code&gt;widgets_init&lt;/code&gt; action in WordPress, and in the function it calls &lt;code&gt;unregister_widget()&lt;/code&gt; on the widget to remove, the meta widget in this case.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function unregister_widgets() {
  unregister_widget( &apos;WP_Meta&apos; );
}
add_action( &apos;widgets_init&apos;, &apos;unregister_widgets&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where do we know to get the class of the widget though? For all of the WordPress core widgets, you can &lt;a href=&quot;https://codex.wordpress.org/Function_Reference/unregister_widget&quot;&gt;reference the codex&lt;/a&gt;, where all of the widget names are listed. Each starts with &lt;code&gt;WP_&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What about widgets that come from other sources, such as a plugin or theme? That can take a little more work. The first and easiest way is to search the source code, and see if you can find where &lt;code&gt;register_widget()&lt;/code&gt; is being called. In Sublime Text or Atom, you could perform a Find in Files for anywhere that &lt;code&gt;register_widget&lt;/code&gt; appears in the project and grab the class name from there.&lt;/p&gt;
&lt;p&gt;If you don’t have the plugin or theme locally, you could also search the repository on GitHub. Opening the &lt;a href=&quot;https://github.com/Automattic/Jetpack&quot;&gt;Jetpack repository&lt;/a&gt;, the search field in the header will perform searches only within the current repository, so a search for &lt;code&gt;register_widget&lt;/code&gt; there will return the same results as if we had searched in a text editor.&lt;/p&gt;
&lt;p&gt;One last piece is adding a conditional to only unregister widgets if the plugin is actually active. It appears that &lt;code&gt;unregister_widget&lt;/code&gt; fails gracefully if it can’t find the widget class, but it would be better to just ignore it entirely if the plugin or theme isn’t active. This might take a little investigation as well, but you can check to see if the main class of the plugin exists.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if ( class_exists( &apos;Jetpack&apos; ) ) {
  unregister_widget( &apos;Jetpack_Gallery_Widget&apos; );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re unregistering a group of Jetpack widgets, adding this conditional will be much faster than checking for each widget individually.&lt;/p&gt;
</content:encoded></item><item><title>Adding Ajax search to a WordPress theme</title><link>https://samhermes.com/posts/adding-ajax-search-to-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/adding-ajax-search-to-wordpress/</guid><pubDate>Sat, 20 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There are a few plugins that will add Ajax search for you, but what if you wanted to integrate it into your theme yourself for more control over functionality and appearance? Let’s see what we can do.&lt;/p&gt;
&lt;p&gt;I’ve broken out the functionality into separate files, which keeps this feature modular. We’ll be creating &lt;code&gt;ajax-search.php&lt;/code&gt; and &lt;code&gt;ajax-search.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before starting, there are a few things we need to do elsewhere first. The following will output the URL of the Ajax file that is part of WordPress core, and needs to be included in &lt;code&gt;functions.php&lt;/code&gt;. We’ll use this in &lt;code&gt;ajax-search.js&lt;/code&gt; to send requests for search results.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wp_localize_script( &apos;ajax-search&apos;, &apos;ajaxurl&apos;, admin_url( &apos;admin-ajax.php&apos; ) );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll want to customize the &lt;code&gt;ajax-search&lt;/code&gt; bit to work with your naming structure. You’ll be less likely to run into conflicts if you use &lt;code&gt;[theme-name]-ajax-search&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Next, I’ve added a loading icon inside the search field to let users know that their request is being processed. I have a custom &lt;code&gt;search-form.php&lt;/code&gt; defined in the theme that adds an animated SVG with a style property of &lt;code&gt;display: none;&lt;/code&gt;. This ensures that the icon will only be show when we’re ready.&lt;/p&gt;
&lt;p&gt;Now, for creating the files. I’m going to start with &lt;code&gt;ajax-search.php&lt;/code&gt;. This is where the template will be stored for the search results. Here we can control what is returned, add a thumbnail, excerpt, date, author, or simply return the title. There’s just one function in this file, and it attaches to the &lt;code&gt;wp_ajax_&lt;/code&gt; hook in WordPress.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function ajax_search() {
  // Get search term from search field
  $search = sanitize_text_field( $_POST[ &apos;query&apos; ] );

  // Set up query using search string, limit to 8 results
  $query = new WP_Query(
    array(
      &apos;posts_per_page&apos; =&amp;gt; 8,
      &apos;s&apos; =&amp;gt; $search
    )
  );

  $output = &apos;&apos;;

  // Run search query
  if ( $query-&amp;gt;have_posts() ) {
    while ( $query-&amp;gt;have_posts() ) : $query-&amp;gt;the_post();

      /* Output a link to each result
         This is where the post thumbnail, excerpt, or anything else could be added */
      echo &apos;&amp;lt;a href=&quot;&apos; . get_permalink() . &apos;&quot;&amp;gt;&apos; . get_the_title() . &apos;&amp;lt;/a&amp;gt;&apos;;

    endwhile;

    // If there is more than one page of results, add link to the full results page
    if ( $query-&amp;gt;max_num_pages &amp;gt; 1 ) {
      // We use urlencode() here to handle any spaces or odd characters in the search string
      echo &apos;&amp;lt;a class=&quot;see-all-results&quot; href=&quot;&apos; . get_site_url() . &apos;?s=&apos; . urlencode( $search ) . &apos;&quot;&amp;gt;View all results&amp;lt;/a&amp;gt;&apos;;
    }

  } else {

    // There are no results, output a message
    echo &apos;&amp;lt;p class=&quot;no-results&quot;&amp;gt;No results&amp;lt;/p&amp;gt;&apos;;

  }

  // Reset query
  wp_reset_query();

  die();
}

/* We need to hook into both wp_ajax and wp_ajax_nopriv_ in order for
   the search to work for both logged in and logged out users. */
add_action( &apos;wp_ajax_ajax_search&apos;, &apos;ajax_search&apos; );
add_action( &apos;wp_ajax_nopriv_ajax_search&apos;, &apos;ajax_search&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The contents of &lt;code&gt;ajax-search.php&lt;/code&gt; could be included inside of &lt;code&gt;functions.php&lt;/code&gt;, but keeping it separate makes &lt;code&gt;functions.php&lt;/code&gt; cleaner and easier to understand.&lt;/p&gt;
&lt;p&gt;Up next, let’s spend some time with the JavaScript to make it work. This example relies on jQuery, but could be reworked to use vanilla JavaScript. Essentially, we listen to the search field for changes. We’ll debounce the number of requests that can be made, but ensure that the user knows that we’re working nonetheless.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jQuery(document).ready( function($) {

  // Set up variables for each of the pertinent elements
  var $searchWrap = $(&apos;.search-form&apos;),
      $searchField = $(&apos;.search-form .search-field&apos;),
      $loadingIcon = $(&apos;.search-form .loading&apos;),
      termExists = &quot;&quot;;

  // Debounce function from https://davidwalsh.name/javascript-debounce-function
  function debounce(func, wait, immediate) {
    var timeout;
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      var callNow = immediate &amp;amp;&amp;amp; !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) func.apply(context, args);
    };
  };

  // Add results container and disable autocomplete on search field
  $searchWrap.append(&apos;&amp;lt;div class=&quot;results&quot;&amp;gt;&amp;lt;/div&amp;gt;&apos;);
  var $searchResults = $(&apos;.search-form .results&apos;);
  $searchField.attr(&apos;autocomplete&apos;, &apos;off&apos;);

  // Perform search on keyup in search field, hide/show loading icon
  $searchField.keyup( function() {
    $loadingIcon.css(&apos;display&apos;, &apos;block&apos;);

    // If the search field is not empty, perform the search function
    if( $searchField.val() !== &quot;&quot; ) {
      termExists = true;
      doSearch();
    } else {
      termExists = false;
      $searchResults.empty();
      $loadingIcon.css(&apos;display&apos;, &apos;none&apos;);
    }
  });

  // Make search Ajax request every 200 milliseconds, output results
  var doSearch = debounce(function() {
    var query = $searchField.val();
    $.ajax({
      type: &apos;POST&apos;,
      url: ajaxurl, // ajaxurl comes from the localize_script we added to functions.php
      data: {
        action: &apos;ajax_search&apos;,
        query: query,
      },
      success: function(result) {
        if ( termExists ) {
          // `result` here is what we&apos;ve specified in ajax-search.php
          $searchResults.html(&apos;&amp;lt;div class=&quot;results-list&quot;&amp;gt;&apos; + result + &apos;&amp;lt;/div&amp;gt;&apos;);
        }
      },
      complete: function() {
        // Whether or not results are returned, hide the loading icon once the request is complete
        $loadingIcon.css(&apos;display&apos;, &apos;none&apos;);
      }
    });
  }, 200);

});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That just about does it. The last piece is styling for the results. You’re likely to have plenty of ideas of your own, so I&apos;ll close this up here. If there&apos;s anything I&apos;ve missed or been a bit unclear about, direct a tweet to &lt;a href=&quot;https://twitter.com/samhermes&quot;&gt;@samhermes&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Communicating about the web</title><link>https://samhermes.com/posts/communicating-about-the-web/</link><guid isPermaLink="true">https://samhermes.com/posts/communicating-about-the-web/</guid><pubDate>Sat, 06 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The longer that I work in web development, the more time I spend thinking about the communication that surrounds the work I’m doing. How do I talk about what I’ve done? How do I best explain how to use a feature or tool? What happens when I’m no longer working on this project? The language that we use, whether we’re talking to another developer, a designer, or a user, is really important.&lt;/p&gt;
&lt;p&gt;For communicating with other developers, it just gets more and more important to be succinct. The fewer words I can use to explain something, the better. This is true in commit messages, code comments, and documentation. I know it’s important because I really appreciate it when others do it. It might take me a little more time to edit, but depending on how many people are involved, it can save a lot of others’ time.&lt;/p&gt;
&lt;p&gt;Slowly over time, I’ve been trying to cut out my use of the word ‘just’ and other similar terminology. Others have said this, but it’s unhelpful in that assumes that a process is easier than it may be for the reader. It subtly gives the writer the role of the expert, when it would be better to attempt to meet someone where they are. It’s something I’m working on.&lt;/p&gt;
&lt;p&gt;Beyond the day to day, I’m also challenged and interested in how to communicate to a larger, slightly undefined audience. In some cases, it’s hard to know who has or who will read what you’ve written. For on-boarding developers or users, how do I write broadly and generically while still being laser focused on the topic at hand? How do I write a commit or a pull request with enough information without taking up too much of my time? Or, how do I explain how to use a feature when my words could possibly be copied and shared with others?&lt;/p&gt;
&lt;p&gt;The web is more fun when everyone is included, and that includes everything about the web. The more we build, the more we have to keep others in mind. After all, &lt;a href=&quot;https://www.smashingmagazine.com/2017/03/world-wide-web-not-wealthy-western-web-part-1/&quot;&gt;you don’t know where your next users will come from&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Using next_posts_link() and prev_posts_link() on static front page</title><link>https://samhermes.com/posts/next-posts-link-prev-posts-link-static-front-page/</link><guid isPermaLink="true">https://samhermes.com/posts/next-posts-link-prev-posts-link-static-front-page/</guid><pubDate>Mon, 24 Apr 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you have a custom query of posts on a static front page in WordPress, adding pagination can be a confusing experience. The answer is fairly simple, if you’ve done it before. Prior to last week, I had not done it before, and I was very lost. Search results were driving me all kinds of places. Fortunately, you’ve landed here.&lt;/p&gt;
&lt;p&gt;The issue is that the &lt;code&gt;paged&lt;/code&gt; query variable isn’t called &lt;code&gt;paged&lt;/code&gt; on the homepage, but rather &lt;code&gt;page&lt;/code&gt;. Both &lt;code&gt;next_posts_link()&lt;/code&gt; and &lt;code&gt;prev_posts_link()&lt;/code&gt; utilize the query variable, and a custom query is looking for the &lt;code&gt;paged&lt;/code&gt; variable. To remedy this, you need to alter your query. In my specific case, the template partial could be used on a static front page or on any other page. Because of that, the following checks to see which is appropriate to use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;global $paged;

if ( get_query_var( &apos;paged&apos; ) ) {
  $paged = get_query_var( &apos;paged&apos; );
} elseif ( get_query_var( &apos;page&apos; ) ) {
  $paged = get_query_var( &apos;page&apos; );
} else {
  $paged = 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the &lt;code&gt;$paged&lt;/code&gt; variable has been properly set, both &lt;code&gt;next_posts_link()&lt;/code&gt; and &lt;code&gt;prev_posts_link()&lt;/code&gt; will work as expected.&lt;/p&gt;
&lt;p&gt;I’ll note that &lt;code&gt;paginate_links()&lt;/code&gt; works without making the modification I’ve outlined, if that’s the pagination structure you’re looking for. In my case, it was a bit more than I needed.&lt;/p&gt;
</content:encoded></item><item><title>We don’t need AMP</title><link>https://samhermes.com/posts/we-dont-need-amp/</link><guid isPermaLink="true">https://samhermes.com/posts/we-dont-need-amp/</guid><pubDate>Thu, 16 Mar 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://shoptalkshow.com/episodes/248-amp/&quot;&gt;Episode #248 of Shop Talk Show&lt;/a&gt; is all about AMP (accelerated mobile pages) and how the project relates to the web at large. After listening, I have some thoughts. It’s made fairly clear in the episode that AMP is a crutch used by publishers who have lost control of their website’s performance. AMP has a very tight set of constraints built into it that prioritize performance. Comparing it to a traditional website, it makes sense why it is so effective. The defeating part of it is that it doesn’t have to exist. We can make pages that are better than AMP on the web.&lt;/p&gt;
&lt;p&gt;Development teams have been fighting constraints as long as the web has existed, and sometimes performance just doesn’t win out. Now they’ve been presented with, essentially, an easy way out. Instead of reprioritizing performance internally, AMP can be used to make the case for performance, and it wins out because it puts you in a good place with Google. This isn’t a good for the long-term.&lt;/p&gt;
&lt;p&gt;The guests in the episode don’t seem to be able to defend the AMP project very well, and it’s a bit hard to get on board listening to the discussion. It reeks a bit of “business reasons,” which is never a good reason in itself to do something. The fact of the matter is, AMP doesn’t need to exist. What we should be doing is using AMP as a model to improve what we already have. We should be removing as much code as possible from our sites, simplifying the layout, and caching as much as we possibly can. The future of the web depends on it.&lt;/p&gt;
&lt;p&gt;&amp;lt;strong&amp;gt;Update 3/25/17:&amp;lt;/strong&amp;gt; An excellent roundup of the debate over AMP was posted on CSS-Tricks just the other day, it&apos;s at &lt;a href=&quot;https://css-tricks.com/need-catch-amp-debate/&quot;&gt;css-tricks.com/need-catch-amp-debate&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>The two worlds of web development</title><link>https://samhermes.com/posts/two-worlds-web-development/</link><guid isPermaLink="true">https://samhermes.com/posts/two-worlds-web-development/</guid><pubDate>Mon, 13 Mar 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There’s a big divide in the web development community that doesn’t get discussed enough. It’s roughly the difference between those who develop sites for informational purposes and those who develop sites that are applications. In some ways, it’s the divide between front end and back end development. It’s a bit difficult to draw a line between the two worlds, but informational sites are usually those for organizations, businesses, government, etc., and applications are properties like Airbnb, Facebook, and Google Docs. Interactivity, such as filtering, liking, saving, editing, or sorting, is usually what takes it from informational to application. The way we talk about and teach web development often mixes these two or makes no distinction.&lt;/p&gt;
&lt;p&gt;There are fundamental differences in the way we approach development in the two worlds. I’ve often gotten caught in this myself. Developing CSS for a web application is infinitely more complex than developing CSS for a static site mostly consisting of pages. Typically, if a project has a small team of developers working on it, CSS naming techniques such as BEM or OOCSS are not necessary. In fact, they are likely adding undue complexity and bloat to the site. In addition, a future developer would need to be briefed on how CSS works in that specific project.&lt;/p&gt;
&lt;p&gt;The same problem exists with JavaScript frameworks. An informational site rarely calls for a framework, and only sometimes calls for jQuery or another library. To develop an informational site using React, we’ve introduced a great deal of complexity that will require a level of maintenance that likely outweighs the perceived benefits. React makes sense for those sites that absolutely call for it, where we need to break apart each and every piece of a page into small, maintainable components. In addition, for someone new to web development, it may seem like React is required knowledge. We talk about it often, making it seem like a core piece of the web. In reality, it’s not. It’s simply the thing that there is a lot to learn about at the moment.&lt;/p&gt;
&lt;p&gt;Many of the foremost developers working in our industry are no longer solving problems for information-based sites. The pressing issues are how to handle a site when there are an innumerable amount of views and states, from all of the different ways to view a single post, photo, or conversation. And what about these views at each breakpoint? What if the user is not logged in? On top of that, how do we handle small updates with a team of 30 developers and keep everyone in sync? Many of the articles that get written and shared are answers to these big problems. While it’s fantastic to be aware of this work, it would be better if we had a bit of context before adapting it for ourselves. At the very least, we should take some time to consider whether or not the practices being put forth are appropriate for our world.&lt;/p&gt;
</content:encoded></item><item><title>The long game of web development</title><link>https://samhermes.com/posts/the-long-game-of-web-development/</link><guid isPermaLink="true">https://samhermes.com/posts/the-long-game-of-web-development/</guid><pubDate>Sun, 01 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently finished reading &lt;em&gt;The World Beyond Your Head&lt;/em&gt; by Matthew B. Crawford, and in the book he speaks of observing the individuals working as organ builders. He tells of the slowness of the process, much done by hand, then spends a bit of time musing on the long game of organ building. In it, one must respect the work of the person who came before, and also think of the person who will be maintaining the organ, and learning from their work in the future.&lt;/p&gt;
&lt;p&gt;Throughout, I couldn’t stop myself from paralleling organ building with web development, as I am wont to do. Web development depends so heavily on the past and the future, both respecting the standards and best practices that came before, and looking to the future and working in a way that will allow for flexibility down the line. Compared to building an organ, all of this is happening in a heavily compressed amount of time.&lt;/p&gt;
&lt;p&gt;In making the parallel, and taking it a little further, I was incredibly inspired by the following, taken straight from the book:&lt;/p&gt;
&lt;p&gt;“The preparation—getting the cutups right, getting them straight, manipulating the windway sizes and the toe holes—you could train a monkey to do that sort of thing. Just give them the list and they do it. If that’s done really really well, that’s ninety-seven percent of the work. After that ninety-seven percent is finished, the pipe will make a sound, it’ll play. Getting it to play beautifully, that’s the last three percent. And that’s where I’d like to say the artistic integrity of the voicer is put to use, and it’s at that point where the good voicer who has done really well preparing the pipes can take all the math and all the science, if they so desire, and you can start to throw some of that out the window. Now we’re not in the science book anymore, we’re not studying the math, now we’re making music.”&lt;/p&gt;
&lt;p&gt;It’s impossible to take web development seriously without great attention to the design, and design is music. The organ builders are involved in a tedious operation that ultimately results in music. Web developers spend months preparing a site the results in design. It’s design that hits the screen, not the development. No matter what you did in development, does it create music?&lt;/p&gt;
&lt;p&gt;Maybe the numbers all add up, they make sense, they’ve been engineered to perfection. Is the website a technical feat, it’s perfectly functional, but it just doesn’t seem to have a point of view? It’s easy to get caught up in the engineering of a website so much that the product of all that work doesn’t present itself as an emotional experience. And isn’t that what we’re doing on the web? If we were to throw emotion and perspective and impact out the window, we wouldn’t have much use for CSS. Why would we get halfway there and then give up when we’re so close?&lt;/p&gt;
&lt;p&gt;I urge you to spend that last 3 percent, and rebel. Go against the numbers, use your gut. Make something that feels like music. Make something that will inform the future.&lt;/p&gt;
</content:encoded></item><item><title>High density screens and web performance</title><link>https://samhermes.com/posts/high-density-screens-web-performance/</link><guid isPermaLink="true">https://samhermes.com/posts/high-density-screens-web-performance/</guid><pubDate>Mon, 05 Dec 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;High density screens and the web are at odds. On one side, we want sites to look as crisp as possible, no matter where they are being viewed, but on the other hand, performance is incredibly important. Actually, most important.&lt;/p&gt;
&lt;p&gt;Say that we begin preparing images for 2x devices. We serve up images that are four times bigger in file size, and they look great on a Retina MacBook Pro. That&apos;s great. But, look at it on a 5K iMac, and we&apos;re essentially back to square one. Also, we forgot to ask, but did that MacBook Pro user want to download an image that was four times bigger? Maybe they were on a slow connection and did not really care to. Should we be making those decisions for them at this point? I think we should be waiting for browsers to get smarter about this.&lt;/p&gt;
&lt;p&gt;Currently, my goal is to prepare everything, except for photos, for any pixel density. I think that by leaving photos at or slightly above their display size, it optimizes for web performance. Photos are the hardest to tell if they are not at the correct pixel density. If there is text in an image, it should be served up in higher density. Otherwise, 1x is good enough for now.&lt;/p&gt;
&lt;p&gt;I think sites are in good shape if they convert all remaining graphical elements to vector, including interface controls. If you can do it in a vector graphic, it&apos;s ready for the future. Right now, the support for SVG is fantastic, and they are fairly performant. I think they are what I am most excited about on the web at the moment.&lt;/p&gt;
</content:encoded></item><item><title>How to configure a sticky header to prevent page jump</title><link>https://samhermes.com/posts/how-to-configure-sticky-header-to-prevent-page-jump/</link><guid isPermaLink="true">https://samhermes.com/posts/how-to-configure-sticky-header-to-prevent-page-jump/</guid><pubDate>Thu, 10 Nov 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As I’ve been out browsing the web lately, I’ve come across quite a few sticky headers that are implemented in a way that causes the page to jump up as scrolling begins. They are statically positioned at the top of the page, and then convert to fixed position when the page is scrolled down to a certain point. That works well, except removing an element from its position in the page leaves a gap, and that gap will close immediately after the element is removed, causing the page to jump up.&lt;/p&gt;
&lt;p&gt;Fortunately, the fix is simple and straightforward. We must simply fill the gap left by a sticky header. We can fill it in a number of ways, a few of which I will detail now.&lt;/p&gt;
&lt;h3&gt;Apply padding to the top or bottom of the nearest element&lt;/h3&gt;
&lt;p&gt;This works well if you have an stable environment in which to do it. If the header is the same across the entire site, you can be certain that this will always give you the desired outcome. Right next to the JavaScript that you are using to change the positioning of the header, just grab a calculation of the current height of the sticky element and apply that value as top or bottom padding to the nearest element. &lt;em&gt;dusts off hands, walks away&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var navHeight = document.getElementById(&apos;site-header&apos;).offsetHeight,
  page = document.getElementById(&apos;page&apos;);

page.style.paddingTop = navHeight + &apos;px&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keep in mind that &lt;code&gt;.offsetHeight&lt;/code&gt; will include padding and border, but not margin.&lt;/p&gt;
&lt;h3&gt;Add an empty &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; after the sticky header&lt;/h3&gt;
&lt;p&gt;This method is used by Stickyfill, which I’ve written about before. This method is a little more flexible if you’re looking to make multiple items sticky or if you aren’t sure what elements will be reliably above or below the header. Rather than reinventing a wheel, add Stickyfill to your project and follow its implementation. It does an excellent job and won&apos;t lead to issues with page jump.&lt;/p&gt;
</content:encoded></item><item><title>Preparing SVG for the web</title><link>https://samhermes.com/posts/preparing-svg-for-the-web/</link><guid isPermaLink="true">https://samhermes.com/posts/preparing-svg-for-the-web/</guid><pubDate>Wed, 14 Sep 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I used to be really scared of using SVG, and now I’m just a little bit scared. I think the scary part is that you can easily see the mess inside. It’s all right there, open to edit and optimize. I’ve been working with SVG for a while now, and I’ve come to rest on what I’ve found to be the best way to prepare them for the web. As they are complex, these may not be the best in each and every case, but this is what works for me.&lt;/p&gt;
&lt;h3&gt;Saving from Illustrator&lt;/h3&gt;
&lt;p&gt;I followed the save dialog example given in the &lt;a href=&quot;https://css-tricks.com/using-svg/&quot;&gt;CSS Tricks article on using SVG&lt;/a&gt; for a while before I got comfortable with it. The article doesn&apos;t get into details of the options, so let me step through those. You’ll have to toggle the ‘More Options’ button to get to all of these.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SVG Profile&lt;/strong&gt;&amp;lt;br&amp;gt;
Set this to SVG 1.1, which is the current supported version in modern browsers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS Properties&lt;/strong&gt;&amp;lt;br&amp;gt;
There’s not a big difference between using a style element, or applying presentation attributes, but I like to use presentation attributes. It makes the resulting document cleaner, and doesn’t muddy it up with classes. We already have enough classes. If you’re going to inline the SVG and use CSS to add additional styles, then classes are the way to go. For static images, presentation attributes make the most sense to me.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decimal Places&lt;/strong&gt;&amp;lt;br&amp;gt;
You’ll want to adjust the amount of decimals on an image by image basis, as some images will break down if you use too few, but it’s always better for performance if you use fewer. I like to get down to about 1 or 2 if possible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checkboxes&lt;/strong&gt;&amp;lt;br&amp;gt;
I hate to generalize, but if there’s a checkbox with a check in it, uncheck it. We don’t want to preserve editing capabilities, include slicing data or XMP, or make it responsive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Much of this I was able to verify using an &lt;a href=&quot;http://stackoverflow.com/questions/13236365/optimal-settings-for-exporting-svgs-for-the-web-from-illustrator&quot;&gt;incredibly helpful answer given on Stack Overflow&lt;/a&gt;. It details even further the reasons behind settings, and talks about fonts and images, both of which don’t really seem to belong inside of an SVG.&lt;/p&gt;
&lt;p&gt;Once the SVG has been saved from Illustrator, further optimization is necessary. Illustrator includes a generator comment inside the SVG, and does not do any minimization.&lt;/p&gt;
&lt;h3&gt;Optimizing for the web&lt;/h3&gt;
&lt;p&gt;Illustrator gives you a big glob of stuff that you do not need, or want to send down the pipe. SVG is already a little heavier than a PNG anyway, depending, so it’s important to make it as slim as possible.&lt;/p&gt;
&lt;p&gt;I use SVGO on the command line to optimize all SVGs. It works great, and I’ll give it credit for warming me up to the command line in general. You just type &lt;code&gt;svgo&lt;/code&gt;, a space, drag and drop the file onto the terminal window, and hit enter. Done. It will tell you what percentage it has shaved off, which always feels awesome. There is also a web interface, created by Jake Archibald, that will perform the same tasks. It’s accessible at &lt;a href=&quot;https://jakearchibald.github.io/svgomg&quot;&gt;https://jakearchibald.github.io/svgomg&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;A few things you’ll want to look out for:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Make sure that the height and width are set inside the SVG, not just in CSS. This improves compatibility across browsers. Can I use reports an issue in IE 9–11 where SVGs don’t scale properly without height, width, viewBox, and CSS rules specified, and I’ve had an SVG without height and width collapse to about 3px tall on an older Android device.&lt;/li&gt;
&lt;li&gt;It’s best if the viewBox attribute starts with &lt;code&gt;0 0&lt;/code&gt;, followed by the width and height of the graphic. This puts the origin of the graphic at the natural origin and matches the viewport to the height and width. A fantastic, thorough explanation of this has been written by Sara Soueidan at &lt;a href=&quot;https://sarasoueidan.com/blog/svg-coordinate-systems&quot;&gt;https://sarasoueidan.com/blog/svg-coordinate-systems&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Adding syntax highlighting to code</title><link>https://samhermes.com/posts/adding-syntax-highlighting-to-code/</link><guid isPermaLink="true">https://samhermes.com/posts/adding-syntax-highlighting-to-code/</guid><pubDate>Thu, 25 Aug 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When I started working on the last iteration of my site, I knew I was going to need to figure out how to display code snippets. I considered using Github Gists or Codepen, but they both seemed to be a bit overkill. Also, I wanted control over the appearance and formatting.&lt;/p&gt;
&lt;p&gt;If I wasn’t going to be embedding the code, that meant I would need to add it directly to the post, wrap it in &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; tags, and style it. I could handle the first two steps, but needed help styling it. There are a number of JavaScript libraries that will apply syntax highlighting to your code, but I landed on &lt;a href=&quot;http://prismjs.com&quot;&gt;Prism.js&lt;/a&gt;. It was the lightest option, and was the easiest to tweak the styles of. I am using the Okaidia theme and added PHP to the list of default languages.&lt;/p&gt;
&lt;p&gt;Since I’m using Jekyll to build my site, I wasn’t sure how to conditionally include Prism only on the posts I’m using code snippets in. Using an &lt;a href=&quot;http://mattgemmell.com/page-specific-assets-with-jekyll/&quot;&gt;article by Matt Gemmell&lt;/a&gt;, I added YAML front matter that specified the name of the JavaScript file to include.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;custom_js: prism
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, in the footer, I added a &lt;code&gt;for&lt;/code&gt; loop that added a script tag for each javascript file included.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{% raw %}{% if page.custom_js %}
  {% for js_file in page.custom_js %}
&amp;lt;script src=&apos;/js/{{ js_file }}.js&apos; type=&quot;text/javascript&quot;&amp;gt;&amp;lt;/script&amp;gt;
  {% endfor %}
{% endif %}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prism comes with the appropriate styles bundled with it, which I just copied and included in my main stylesheet, tweaking them slightly.&lt;/p&gt;
&lt;p&gt;With Prism running on the page, all that’s needed to properly activate it is the appropriate class for the language of the code snippet. For the above snippet, I added &lt;code&gt;class=&quot;language-markup&quot;&lt;/code&gt; to the &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt;  element to add the appropriate highlighting. Now when making a new post, I just need to include the YAML front matter and add a class, and that&apos;s it!&lt;/p&gt;
</content:encoded></item><item><title>What changes on hover should be actionable</title><link>https://samhermes.com/posts/what-changes-on-hover-should-be-actionable/</link><guid isPermaLink="true">https://samhermes.com/posts/what-changes-on-hover-should-be-actionable/</guid><pubDate>Sun, 07 Aug 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This falls clearly in the realm of opinion, but I thought I’d share my thoughts anyway. If an item has a hover state, that hover state should highlight the part of the item that an action can be taken on. To illustrate this, I’ve created an example card. When hovering over the card, an outline appears. However, only the link at the bottom is actionable.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;card-container&quot;&amp;gt;
&amp;lt;div class=&quot;card&quot;&amp;gt;
&amp;lt;h1&amp;gt;Porano Pasta&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;Fast Casual Italian&amp;lt;/p&amp;gt;
&amp;lt;a href=&quot;http://poranopasta.com&quot;&amp;gt;Visit Site&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;Hover states are becoming less and less important, but I still feel that this requires some consideration. I think that anything that changes when you hover over it should be one link. If there are multiple links within the element, then there should be no hover effect applied. Again, the card example, but with the link covering the entire element.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;card-container&quot;&amp;gt;
&amp;lt;a href=&quot;http://poranopasta.com&quot;&amp;gt;
&amp;lt;div class=&quot;card&quot;&amp;gt;
&amp;lt;h1&amp;gt;Porano Pasta&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;Fast Casual Italian&amp;lt;/p&amp;gt;
&amp;lt;p class=&quot;action&quot;&amp;gt;Visit Site&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;Usually, as a page is navigated, the hover states are what indicates that something is actionable, so keeping this behavior will provide a more cohesive experience.&lt;/p&gt;
&lt;p&gt;&amp;lt;style&amp;gt;.card-container {
background: #f3f3f3;
padding: 25px;
margin-bottom: 30px;
}&lt;/p&gt;
&lt;p&gt;.card {
margin: 0 auto;
max-width: 250px;
padding: 15px;
transition: 0.2s;
background: #fff;
border-radius: 3px;
box-shadow: 0 2px 20px 0 rgba(0, 0, 0, 0.1);
border: 1px solid transparent;
}&lt;/p&gt;
&lt;p&gt;.card:hover {
border: 1px solid tomato;
}&lt;/p&gt;
&lt;p&gt;.card h1 {
margin: 0 0 15px;
font-size: 1.75em;
line-height: 1;
}&lt;/p&gt;
&lt;p&gt;.card p {
margin: 0 0 35px;
font-size: 1em;
}&lt;/p&gt;
&lt;p&gt;.card a,
.card .action {
color: tomato;
text-decoration: none;
text-transform: uppercase;
font-size: 14px;
margin: 0;
border: 0;
}&lt;/p&gt;
&lt;p&gt;.card-container &amp;gt; a {
display: block;
margin: 0 auto;
max-width: 280px;
border: 0;
color: #1D1D1D;
text-decoration: none;
}&lt;/p&gt;
&lt;p&gt;.card-container &amp;gt; a:hover {
text-decoration: none;
}&amp;lt;/style&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Sticky elements with Stickyfill</title><link>https://samhermes.com/posts/sticky-elements-with-stickyfill/</link><guid isPermaLink="true">https://samhermes.com/posts/sticky-elements-with-stickyfill/</guid><pubDate>Sun, 24 Jul 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sticky elements seem to be everywhere, following you wherever you scroll. There are many ways to implement sticky positioning, but as support comes to browsers natively, the best way right now is to use a polyfill. This is where Stickyfill comes in. If &lt;code&gt;position: sticky&lt;/code&gt; is not supported, it mimics the behavior. As soon as support comes to all major browsers, the polyfill can be removed. At the moment, it is supported in Firefox and Safari, and is behind a flag in Chrome and Opera. Considering that it is most commonly used on larger screens, the support is strong.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://github.com/wilddeer/stickyfill&quot;&gt;download Stickyfill on Github&lt;/a&gt;. There is a demo and a few use cases provided. I’m sure there are some cases where this isn’t the best option, but I think the polyfill approach is best in most implementations.&lt;/p&gt;
&lt;p&gt;Taken directly from the readme, you can hook Stickyfill up with the following JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var stickyElements = document.getElementsByClassName(&apos;sticky&apos;);
for (var i = stickyElements.length - 1; i &amp;gt;= 0; i--) {
  Stickyfill.add(stickyElements[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have been using Stickyfill with a WordPress site, so I have changed the class to simply &lt;code&gt;stick&lt;/code&gt; so that it will not interfere with sticky posts.&lt;/p&gt;
&lt;p&gt;While your implementation may be much more complex, applying the following styles to a sidebar would be all you would need to get started.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.sticky {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my project, I set the value of top to &lt;code&gt;15px&lt;/code&gt; to give a little room above the element. Also, I added an additional selector that would account for the WordPress admin bar, so the value of top is &lt;code&gt;47px&lt;/code&gt; when the &lt;code&gt;.admin-bar&lt;/code&gt; class is present. This makes sure that even users who are signed in see a properly formatted site.&lt;/p&gt;
</content:encoded></item><item><title>Maintaining state with sessionStorage</title><link>https://samhermes.com/posts/maintaining-state-with-sessionstorage/</link><guid isPermaLink="true">https://samhermes.com/posts/maintaining-state-with-sessionstorage/</guid><pubDate>Sun, 24 Apr 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When a multi-level menu is collapsed on a small screen, it can difficult to communicate a sense of place as someone is navigating between pages. If the page is several levels deep in the hierarchy, it is really frustrating to dig back down to it if you’d like to view a sibling page. One way to manage this is to let the browser remember your location with sessionStorage.&lt;/p&gt;
&lt;p&gt;To start, you need to give a unique ID to each menu item that has children. If you’re working with WordPress, you could use the built in page ID, since you know that it will be unique.&lt;/p&gt;
&lt;p&gt;We only need to keep one ID in sessionStorage at a time, so we listen for a click event on all of the elements serving as a toggle and update sessionStorage each time.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$(&apos;.main-menu li&apos;).click(function() {
  var menu_state = $(this).prop(&apos;class&apos;).match(/page-([0-9]+)/)[1];
  sessionStorage.setItem(&apos;menu_state&apos;, menu_state);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sets the name of the sessionStorage item to be ‘menu_state’, and then stores the ID as the value. As a submenu is toggled, this value is updated. Move to another page, and the last value is still remembered by the browser.&lt;/p&gt;
&lt;p&gt;You can view all of the sessionStorage items that have been set in your browser in the web inspector. In Chrome, go to the Resources tab. In Safari and Firefox, go to the Storage tab. A nice feature of sessionStorage is that the browser clears it as soon as you close the page.&lt;/p&gt;
&lt;p&gt;Retrieving a value from sessionStorage is very similar to setting it. We perform this action when the document is ready instead of waiting for a click event.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var menu_state = sessionStorage.getItem(&apos;menu_state&apos;);
if( menu_state ) {
  $(&apos;.page-&apos; + menu_state).addClass(&apos;open&apos;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This applies a class of &lt;code&gt;open&lt;/code&gt; to the menu that was open on the last page. Now, given that &lt;code&gt;open&lt;/code&gt; has a bit of CSS behind it, when someone opens the mobile menu, they’ll still be in the same place where they were. Magic.&lt;/p&gt;
</content:encoded></item><item><title>Caching a menu in a transient in WordPress</title><link>https://samhermes.com/posts/caching-menu-in-transient-in-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/caching-menu-in-transient-in-wordpress/</guid><pubDate>Wed, 30 Mar 2016 21:38:00 GMT</pubDate><content:encoded>&lt;p&gt;Menus in WordPress are expensive to generate, in terms of site performance. On every page load, the site is rebuilding almost the exact same thing, and it gets more expensive as the number of menu items increases. The only difference between pages is the current page classes that get applied. What if we stored the menu in a transient, and applied the current page classes on the front end using JavaScript?&lt;/p&gt;
&lt;p&gt;The first thing we do is check to see if the transient doesn’t exist with a conditional (which it doesn’t, yet), using get_transient and passing in the name of the transient, which we’ll specify later.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if ( ! get_transient( &apos;header-menu&apos; ) ) {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, if the transient doesn’t exist (which it doesn’t, yet), we generate the menu, and store the result in a variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$menu = wp_nav_menu( array(
  &apos;theme_location&apos; =&amp;gt; &apos;header-menu&apos;,
  &apos;echo&apos; =&amp;gt; 0
) );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to disable echo here, as we don’t want to print it to the page just yet.&lt;/p&gt;
&lt;p&gt;Once we have the menu stored in a variable, we can set a transient. This part of the process is relatively simple. You give the transient a name, pass in the menu variable, and tell it how long to keep it before clearing it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set_transient( &apos;header-menu&apos;, $menu, 60*60*24 );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, I’ve named the transient “header-menu”, and told it to save it for 1 day (60 seconds times 60 times 24). I’m not sure what the ideal transient lifetime is, but if the menu will rarely change, you could set it for much longer than a day.&lt;/p&gt;
&lt;p&gt;Next, continuing with the conditional, if the transient does exist, we just need to retrieve it and set it to the menu variable. And, after that, we echo out the menu variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;} else {
  $menu = get_transient( &apos;header-menu&apos; );
}
echo $menu;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last piece of the transient is clearing it whenever an update is made to the menu. This function can be added to functions.php. This function looks for a menu in the ‘header-menu’ menu location.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function site_nav_clear_transient( $menu_id ) {
  $theme_locations = get_nav_menu_locations();
  $term = get_term( $theme_locations[&apos;header-menu&apos;], &apos;nav_menu&apos; );
  $id = $term-&amp;gt;term_id;
  if ( $menu_id = $id ) {
    delete_transient( &apos;header-menu&apos; );
  }
}
add_action( &apos;wp_update_nav_menu&apos;, &apos;site_nav_clear_transient&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it for the transient, but now we need to reapply the class for the current page. We accomplish that with a little jQuery.&lt;/p&gt;
&lt;p&gt;This approach is fairly simple. On page load, we get the URL of the current page using &lt;code&gt;window.location.href&lt;/code&gt;, store the result in a variable, and then use that variable to find a matching &lt;code&gt;href&lt;/code&gt; attribute. It’s as simple as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var url = window.location.href;
$(&apos;.header-menu a[href=&quot;&apos; + url + &apos;&quot;]&apos;).addClass(&apos;current-page&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The jQuery selector looks for an anchor tag inside of an element with the class of ‘header-menu’, matches the url variable we passed in, and then adds a class of ‘current-page’.&lt;/p&gt;
</content:encoded></item><item><title>Toggling elements with JavaScript</title><link>https://samhermes.com/posts/toggling-elements-with-javascript/</link><guid isPermaLink="true">https://samhermes.com/posts/toggling-elements-with-javascript/</guid><pubDate>Tue, 08 Mar 2016 20:20:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the most performant ways to toggle an element with JavaScript is to apply and remove a class. Paul Irish pointed out last year that using jQuery’s &lt;code&gt;.hide()&lt;/code&gt;, &lt;code&gt;.show()&lt;/code&gt;, and &lt;code&gt;.toggle()&lt;/code&gt; methods are very costly. I’ve used/am currently using each of these, as they are really easy to understand and implement. However, you’ll see that a plain JavaScript approach isn’t too difficult.&lt;/p&gt;
&lt;p&gt;For my site, I needed a toggle for the menu on small screens. I used the following to add and remove a class named ‘open’, which has the proper styles to show the menu. In this case, it is performed when an element with the class of ‘toggle’ is clicked.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var menu = document.querySelector(&apos;.toggle&apos;);
menu.onclick = function() {
  menu.classList.toggle(&apos;open&apos;);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Setting up Jekyll</title><link>https://samhermes.com/posts/setting-up-jekyll/</link><guid isPermaLink="true">https://samhermes.com/posts/setting-up-jekyll/</guid><pubDate>Sat, 13 Feb 2016 07:15:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently switched this site to Jekyll, and I thought I&apos;d share the setup process. Jekyll was a bit slow the last time I used it, so I was excited to find that the 3.0.0 update included speed improvements that make updates available in the browser almost immediately. Here are some of the configuration changes I made outside of the defaults:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changed the permalink structure to &lt;code&gt;/posts/:title/&lt;/code&gt;. I made this update in config.yml, refreshed the site, and nothing changed. A little digging, and I found out that changes to config.yml will not be processed while &lt;code&gt;jekyll serve&lt;/code&gt; is running. You’ll need to ctrl-c and &lt;code&gt;jekyll serve&lt;/code&gt; again.&lt;/li&gt;
&lt;li&gt;I was using m/d/Y to display dates, and so in looking at how to set that up in Jekyll, I found an &lt;a href=&quot;http://alanwsmith.com/jekyll-liquid-date-formatting-examples&quot;&gt;article from Allan W. Smith&lt;/a&gt; that detailed all of the possibilities. It can be accomplished with {% raw %}&lt;code&gt;{{ post.date | date: &quot;%-m/%-d/%Y&quot; }}&lt;/code&gt;{% endraw %}.&lt;/li&gt;
&lt;li&gt;I display excerpts from posts on the homepage, and in order to specify those manually, you can add an &lt;code&gt;excerpt:&lt;/code&gt; declaration to the YAML front matter on each post and specify the excerpt there. It can then be output with {% raw %}&lt;code&gt;{{ post.excerpt }}&lt;/code&gt;{% endraw %}. Jekyll will automatically give you an excerpt, but for posts that start with a code snippet, that was not ideal.&lt;/li&gt;
&lt;li&gt;For posts that include code snippets, I use &lt;a href=&quot;http://prismjs.com/&quot;&gt;prism.js&lt;/a&gt; for formatting. To include the file only on posts that use it, I add &lt;code&gt;custom_js: prism&lt;/code&gt;  to the front matter. In footer.html, I&apos;ve added the following, which takes care of outputting the script tag:
&amp;lt;pre&amp;gt;&amp;lt;code class=&quot;language-markup&quot; style=&quot;background:none;&quot;&amp;gt;{% raw %}{% if page.custom_js %}
{% for js_file in page.custom_js %}&amp;lt;/code&amp;gt;
&amp;lt;code class=&quot;language-javascript&quot; style=&quot;background:none;&quot;&amp;gt;&amp;lt;script src=&apos;/js/{{ js_file }}.js&apos; type=&quot;text/javascript&quot;&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;/code&amp;gt;
&amp;lt;code class=&quot;language-markup&quot; style=&quot;background:none;&quot;&amp;gt;{% endfor %}
{% endif %}{% endraw %}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
This also allows for the possibility of additional js files, so I can just add the name of a file I&apos;d like to include to the &lt;code&gt;custom_js&lt;/code&gt; declaration. Learned this trick on &lt;a href=&quot;http://mattgemmell.com/page-specific-assets-with-jekyll/&quot;&gt;Matt Gemmell&apos;s site&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I wanted my 404 page to live at /404.html. By default, Jekyll takes that and moves it to /404/index.html. To change that, I added &lt;code&gt;permalink: /404.html&lt;/code&gt; to the YAML front matter on the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Phew. That was more that I thought. Hope this helps speed things up for you.&lt;/p&gt;
</content:encoded></item><item><title>Output featured image caption in WordPress</title><link>https://samhermes.com/posts/output-featured-image-caption-wordpress/</link><guid isPermaLink="true">https://samhermes.com/posts/output-featured-image-caption-wordpress/</guid><pubDate>Sat, 30 Jan 2016 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It&apos;s relatively easy and well documented to output a featured image, but getting the caption is a little trickier. Here&apos;s the code I use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$post_thumbnail_caption = get_post( get_post_thumbnail_id() )-&amp;gt;post_excerpt;

if ( ! empty( $post_thumbnail_caption ) ) {
  echo &apos;&amp;lt;p class=&quot;featured-image-caption&quot;&amp;gt;&apos; . esc_html( $post_thumbnail_caption ) . &apos;&amp;lt;/p&amp;gt;&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: If you are expecting to output HTML inside captions, use &lt;code&gt;wp_kses_post()&lt;/code&gt; in place of &lt;code&gt;esc_html()&lt;/code&gt;. While not as performant, it allows the same tags that are allowed inside post content, such as links, italics, bolding, etc.&lt;/p&gt;
&lt;p&gt;&amp;lt;p class=&quot;last-updated&quot;&amp;gt;Last Updated: 2/3/2016&amp;lt;/p&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Add 1 hour to date &amp; time in PHP</title><link>https://samhermes.com/posts/add-one-hour-to-date-and-time-in-php/</link><guid isPermaLink="true">https://samhermes.com/posts/add-one-hour-to-date-and-time-in-php/</guid><pubDate>Mon, 04 Jan 2016 18:00:00 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code&gt;strtotime($time . &apos;+ 1 hour&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is probably the most magical thing I’ve ever done PHP. Pass in the date and time (in this case, in a variable), tell it what you want to do with it, and out comes the updated date and time. I needed to add an hour to the time I was working with. Seems simple until you think about transition to the next day. This function takes care of advancing the date to the next day if necessary.&lt;/p&gt;
</content:encoded></item><item><title>Using vertical height media queries with fixed headers</title><link>https://samhermes.com/posts/using-vertical-height-media-queries-with-fixed-headers/</link><guid isPermaLink="true">https://samhermes.com/posts/using-vertical-height-media-queries-with-fixed-headers/</guid><pubDate>Sun, 03 Jan 2016 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On a site with tall pages, setting up a fixed header can make a lot of sense. Why not use that extra screen real estate? The philosophies of responsive design can and should apply to this as well. Screen height should be taken into account, and fixed headers should be disabled if there is not enough height for them to be useful (although, I would argue that they are never useful).&lt;/p&gt;
&lt;p&gt;Let&apos;s say that the fixed header on a site is 80px tall. Nothing too unruly, but it might get in the way of someone on a smaller laptop as they are browsing your site. In this example, you could set the header to fixed if the viewport is at least 800px tall. Any shorter and let that header scroll away out of sight.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media screen and (min-height: 800px) {
  header {
    position: fixed;
    top: 0;
    left: 0;
  }
  body {
    margin-top: 80px;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll want to replace the space you’re creating when the header is fixed by applying the height of the header as margin-top of the body element.&lt;/p&gt;
&lt;p&gt;To take this a bit further, you could combine this with a max-width media query so that the header would not be fixed below a specified width, something like 600px. In that way, you are only applying a fixed header when there is plenty of room.&lt;/p&gt;
</content:encoded></item><item><title>Designing for every moment</title><link>https://samhermes.com/posts/designing-for-every-moment/</link><guid isPermaLink="true">https://samhermes.com/posts/designing-for-every-moment/</guid><pubDate>Sat, 02 Jan 2016 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Responsive design is truly about each and every point in between the smallest supported viewport and the largest, which leaves a lot of possibilities. If truly designing for a fully responsive experience, you should give attention to the awkward moments of change. One of those moments is when an element comes into contact with the edge of the screen.&lt;/p&gt;
&lt;p&gt;If there is a centered image on the page with no border or additional styles around it, what happens when the width of the browser window is about 10px wider than the image? It leaves a small gutter along each side. Is this an issue? Maybe not. I still think it deserves consideration.&lt;/p&gt;
&lt;p&gt;It depends on the case, but on a few occasions I have adjusted the behavior of those images so that there are no awkward in-between moments. When the image got to have less than 10px on each side, I stretched the image to fill the entire width of the screen. This is usually okay, as long as the image has a little extra resolution to give. Of course, we wouldn&apos;t want to stretch an image beyond it&apos;s natural size.&lt;/p&gt;
&lt;p&gt;If this is applied to an image, this means that there are no situations where the image has a small gutter along each side, which means that each and every moment along the responsive spectrum has been thought of and cared for.&lt;/p&gt;
</content:encoded></item><item><title>Giving back</title><link>https://samhermes.com/posts/giving-back/</link><guid isPermaLink="true">https://samhermes.com/posts/giving-back/</guid><pubDate>Fri, 01 Jan 2016 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Everything I’ve learned about working on the web, I’ve learned on the web. From reading blogs to doing Treehouse courses to simply reading Twitter, it all took place on one website or another. Up to this point, I’ve really only been taking things in. I don’t think it’s a bad thing, I’ve simply been learning as much as I can. However, I think the time has come that I try to give back a little.&lt;/p&gt;
&lt;p&gt;I am switching my website from portfolio to blog, and starting to share what I know. In my experience, when searching for an answer to a specific question, I know that a short, concise post can be all it takes to put the last piece into a puzzle. I’ll be taking that approach, posting snippets of code and quick explanations of how I solved a problem.&lt;/p&gt;
&lt;p&gt;If this is the first post you’ve read here, then there is already more! Head back to posts to read them.&lt;/p&gt;
</content:encoded></item></channel></rss>