Managing reusable blocks

I love reusable blocks! OK, right now everyone is talking about „(Block) Patterns“ and they will be amazing. But many still don’t know about reusable blocks or just don’t know, why they are so useful.

What is a reusable block

Well, as the name indicates, it’s a block that can be reused. Anywhere. And as such a block can also be a group block, a resuable block can make a whole set of block reusable. Once you have created/converted one, you can use the same „content“ on multiple posts, pages or other post types. In the future also in widgets and any other „block enabled areas“.

But how do you find a reusable block? The easiest way is by clicking on any „Add Block“ button (the squares buttons with the plus sign) and then searching for the name or scrolling all the way down:

Screenshot after clicking the "Add Block" button in the top left corner showing the list of available blocks with the custom reusable block at the end of the list.

You can also use the „Search for a block“ using the name of the reusable block (in our example „Contact“) or by using the „forward slash search“ to quickly find it. New to this view is also the „Manage all reusable block“ link at the end, which could previously be found in the „More tools & option“ view:

Screenshot of the "More tools & options", reachable by the three vertical dots in the top right corner..

When you click on one of the links, you will be redirected to the „Blocks“ overview.

Managing the blocks

The list of block look very much like the listing of any othter post type. Well, that’s not really a big surprise, as reusable blocks are saved as a post type wp_block in the database.

Screenshot of the "Blocks" listing in the backend.

From the management list you can choose „Edit“ on an existing block which will open up the block editor where you can change the block and save it. You can also click on „Add new“ which will allow you to create a new reusable block without the new to create a regular one in a post or page and then converting them into a reusable block.

But maybe the two most handy things you can to from here is using the „Export as JSON“ for individual block or the „Import from JSON“. With these tools, you can simply migrate reusable blocks from one WordPress installation to another.

Bonus

If you pay attention to the last screenshot, you might have recognized that „Blocks“ link in the „Tools“ section. This would usually not be there. If you navigate to the listing using one of the links, you will end up being „nowhere“. This listing is hidden and you can’t reach it using the left navigation. Before the two links were put to those places, it was even harder to find that listing. That’s why I wrote a small helper plugin adding the „Blocks“ link shown in the last screenshot to the „Tools“ section. This made it a lot easier for the client to find that list. If you want to add this link yourself, simply download the plugin from GIST and install it.

Conclusion

Even if reusable blocks might not be used as much when we are able to use the new „Patterns“, there are still usecases when we might want to have „synchronized content“ on our sites. Knowing how to get out the most of those blocks and where to find them makes working with them a lot easier.

Prevent staging website from being indexed by search engines

Working on a website, wheater it already went live or is a new project, you should alsways have a copy of the website in staging environment. But you probably don’t want that website being index by search engines. In this blog posts, I will explain some ways to prevent the indexing.

Method 1: Use the default setting

In the dashboard of your website, navigate to „Settings | Reading“. Here you will find the setting „Search Engine Visibility“ with a checkbox to „Discourage search engines from indexing this site“. This will dynamically create a robots.txt file to tell seach engines not to index your site. But as the note says „It is up to search engines to honor this request“, so some search engines might just still index the page.

Method 2: Prevent indexing in the server config

The first method usually work pretty good. There is only one big issue. The setting is stored in the database an can easily being overwritten. How? Well, you might want to import the database from the live website at one time, to see the latest content on your staging. Do you always remember to go back to that setting and enable it again on your staging? You might forget it.

Therefore preventing the indexing in the server configuration is a safer way, as it stays, even when importing a database from live. Simply add the following lines to the configuration:

Header set X-Robots-Tag "noindex"
Header merge X-Robots-Tag "noarchive"

You can do that in the .htaccess of the staging website. This is most useful, when you host it on the same server or you cannot change the global configuration. But you have to be careful not to overwrite the .htaccess file with the one from the live server.

If you have a dedicated staging server and you want to index none of the website hosted there, just add the lines to the global configuration, like the /etc/apache2/apache2.conf or a similar file.

Method 3: Use a maintenance plugin

You could also protect your website from search engines and from other users by using a maintenance plugin. This will usually add a password protection to your site or you have to login, in order to see the website’s content. This can also be useful to give other people access (like the client), but not everyone. This method although has the same issue, that once you import the live website, you have to make sure to reactivate this plugin, as the state of activated plugins is also stored in the database.

Method 4: Use „basic access authentication

With the „basic access authentication“ aka. htaccess protection, you can prevent access to the website without the need of a plugin. With an Apache webserver, you can add a few lines to your .htaccess file and any visitor to you page has to enter a username an password. This method is safe againt imported live databases but when you overwrite the .htaccess from the live website, you have to restore the protection again. Therefore you can also store it in your global (per site) server configuration.

Conclusion

There are many different ways to protect your staging website from being indexed. Whatever method you use, always make sure that the method is still working, after you did an import from live. You can remove websites from search engines, but you have to do it per domain and for every single search engine using their individual tools.

Replace WordPress domain and paths in the database

In the last blog post I explained how I move a WordPress website to another server. In step 7 I told you, that you have t replace the domain in the database. But this is not the only replacement you might have to do. Today’s blog post will give you some more examples of potential replacements and some other things you have to consider.

Let’s have a look at the most basic replacement again. This command will replace the domain in all tables in the database, with the prefix of the current WordPress installation:

wp search-replace "https://staging.example.com" "https://example.com" --all-tables-with-prefix

It will handle replacements in simple strings, as well as in serialized PHP objects. You should also replace the path to the current installation, if it differce between the servers:

wp search-replace "/home/staging.example.com" "/home/example.com" --all-tables-with-prefix

Search for old domain

After you have run the previous commands, the old domain should be replaced in all tables. You can simply check that with another WP-CLI command:

wp db search "https://staging.example.com"

Additional replacements

Unfortunately, many plugins save complex data in other formats. Therefore it’s also advised, to search for the following patterns and replace them, as long as the previous search still returned some values.

Search patternReplacementComment
http://example.comhttps://example.comNew domain without SSL
http://staging.example.comhttps://example.comOld domain without SSL
//staging.example.com//example.comprotocol-relative paths
https:\/\/staging.example.comhttps:\/\/example.comJSON objects (run this for all previous patterns)
@staging.example.com@example.comemail domains (optional, as somethimes not wanted)
staging.example.comexample.comDangerous!
Replacements for domain changes

There are some variants to consider. For the first four are replacements, you should also „escape“ all slashes, as objets might have been stored using a JSON string. Replacing email addresses is optional, as your new system might not use it’s own emails (like when migrating from Live to Staging) or if you don’t want to show them in the frontend with the different domain.

The last replacement seems to be the easiest one, as it would do all the revious replacements in one go. But it could potentially break things, as the domain name might be part of an image name in the media library, which would result in a broken path to that image. So it’s best not just to replace the domain name only.

Additional steps

Themes, plugins or the server could use caches. There are different methods to clean those caches.

Fusion Builder (e.g. Avada Theme)

At „Avada/Themename | Theme Options | Performane | Reset Fusion Caches“, just use the button „Reset Fusion Caches“ to remove all files from the cache.

Autoptimize

In the adminbar, you will find an entry „Autoptimize“ and at the end of that entry a link named „Delete Cache“.

PageSpeed

To flush the PageSpeed cache, you have to connect to your server and run the following command:

touch /var/cache/pagespeed/cache.flush

It might take some seconds for the cache to be fully flushed. After it’s empty, remove the file:

rm /var/cache/mod_pagespeed/cache.flush

For more information on how to flush only parts of the cache, check the PageSpeed docs.

Migrate a WordPress installation in less then 5 minutes

Working on a WordPress project I always develop locally. For many projects, there is also a staging server. So migrating WordPress installations is a very frequent task for me. Therefore a good process is key.

Easy migrations without plugins

When I do migrations, I usually always use the WP-CLI. The only requirement for that is an SSH access to the the destination server. My migration process is done with these few steps:

1. Dump the source database

A WordPress installation has two parts, the database and the file system. To dump the database, all you need to do is using the following command in the WordPress document root folder:

wp db export
Success: Exported to 'wp_project-staging-2020-03-29-a2aa75c.sql'.

The file name starts with the database name, followed by the current date and a random hexadeciml hash. This has will come in handy with the second step.

2. Pack all files on the source

Now we are ready to pack all files on the source. This can easily be done with zip, gzip or any similar tool:

zip -r wp_project-staging-2020-03-29-a2aa75c.zip .

As the file name, we simply use the same as the database dump created, just with .zip instead of .sql as the extension. This will „protect“ the file name from easily being guessed. Don’t just name it dump.zip as otherwise anyone could just download that file.

3. Transfer the file to the new server

Now it’s time to transfer the file to the new server. This can be done in various ways. A very easy one is using curl, wget or similar:

wget https://staging.example.com/wp_project-staging-2020-03-29-a2aa75c.zip

Transfering from a local system you probaly have to use FTP, as you can’t curl/wget from a local domain.

4. Unpack the file on the destination

The next step is obvious. Once all files are transfered, you have to unpack the files. When you have used a zip files, simply run:

unzip wp_project-staging-2020-03-29-a2aa75c.zip

When you have compressed the files in step 2 in the document root, the files should be unpacked in the document root as well and not be in a subfolder.

5. Update the configuration

Before we can use the project on the new project, we have to update the wp-config.php files. Probably only the values prefixed with DB_.

6. Import the database

Now we can import the database. If the database on the new server is not yet, created, either do it with the management tool of your hoster, or simply by using the WP-CLI as well (which only works, if the database user has the privileges to do this):

wp db create

Once the database is created, you can import is as simply as exporting it in step 1, with the corresponding command:

wp db import wp_project-staging-2020-03-29-a2aa75c.sql

7. Update the domain in the database

As you probably know, in a WordPress installations, all domain paths are stored as absolute paths in the database. This is why you have to update the paths. You can use a plugins for that or also use the WP-CLI with this command:

wp search-replace "https://staging.example.com" "https://example.com"

This is the most basic replacement you have to do. In some cases, you also have to do some other replacements. I will cover that one a future blog post.

Conclusion

Migrating a WordPress project should be as easy as fast as possible, if you do it on a regular basis. My approach only takes two commands on the source and 4-5 command on the destination. The parts that usually takes the most times is the packing, transfering and unpacking, which will takes longer, the larger a project’s size is. For a small projects all of that might only take less then 10 seconds each.

I hope with this small guide, you next migrations is done as easily and fast as for me. If you have a different approach, that might be handy, please leave a comment below explaining it.

Thank you WordPress community!

The last week was tough. I mean really tough. Just two weeks ago, I thanked event organizers on this blog. Now I see myself in the exact same situation.

The cancellation of WordCamp Europe 2020

On Thursday evening last week, I had a call with Tess and Jonas, the other two global leads of WCEU 2020 and with Rocío, our mentor, as well as Andrea, who is leading the global WordPress community team.

We discussed a timeline for the next weeks and month with a plan to have a WordCamp Europe in Porto in June this year. On 5 March, things were still looking quite OK. There have been only a few cases in Portugal and only Italy had to deal with many cases in Europe. We decided to continue working on the event in June, as we were optimstic to be able to still have it. We planed to wait for early April to get to a decision.

The last days

After that meeting, things have been getting worse every day. Conferences in Europe have been cancelled. On 9 March, a large Joomla conference in Lisbon had been cancelled, just one week before WordCamp Europe 2020 in Porto.

On 11 March, the global community team made the recommendation to postpone of cancelany event until 1 June. As WCEU 2020 was planed for 4-6 June, this was just before that date.

Finally this Thursday, just a week after our „emergecy call“, we had a video call with all organiezers and we decided to cancel WordCamp Europe 2020 and postpone it to 2021 again in Porto.

Thanks to our community

The reactions that have followed our announcement where overwhelming. There was no one disagreeing with our decicion. We have received countless empathic messages on Twitter and through other channels. Many friends from the WordPress communities reached out to me directly, asking how I feel and offering help.

This is why I love this community. In good and in hard times, we support each other and offer help. This is why the organizing team is looking positively into the future and is working even harder for an amazing WordCamp Europe 2021 in Porto.

Thank you WordPress community ❤

Thank you event organizers!

I was planning to write on a different subject today for this week’s #project26 blog post, but due to recent events I had to write this one today.

WordCamp Asia 2020

February is over and it was an eventful month for me. Or should I say, it was not? I was really looking forward to my first ever trip to Asia, visiting WordCamp Asia in Bangkok, Thailand. It was scheduled for 21 – 23 February and I have booked my flights and hotel, organized my vacation (as it’s not part of my job to visit WordCamps) and prepared myself for a nice and warm time with many old and new friends. But on 12 February, I got the sad news, that WordCamp Asia had to be canceled.

I was lucky to be able to cancel my hotel and flights without any costs, so I canceled my whole trip to Asia for this year.

CloudFest 2020 Hackathon

This month from 14 – 16 March, I will be attending my first real Hackaton. It’s not organizerd only for WordPress community members, but for a broader audience with amazing people from other open source communites and companies specialized in hosting. But I’m also not attending this conference, as CloudFest also has to be canceled.

WordCamp Retreat Soltau 2020

Two years ago, I visited one of my best WordCamps ever. It was not a regular 2-3 days event, where you would meet „from 9 to 5“ for talks and workshop, but spend some days all in one hotel 24/7 with not only talks, but also some cool activities. This retreat was planed to take place every two years and was scheduled for 30 April – 3 Mai. It was scheduled, because also this event has to be canceled/postponed to next year just yesterday.

Thank you organizers!

If you now wonder, why I want to thank the organizers, it’s pretty easy. Sure, I’m feeling very sad not to be able to attend all these amazing events … this year. But all organizing teams said, that they want to continue organizing the event in 2021. Most of them in the same places and around the same time.

I have organized four WordPress conferences in Berlin and am currently organizing WordCamp Europe for the fourth time. I know how much work, time, engery and passion goes into organizing these community events. I can only imagine how hard it must have been for all organizers of those WordCamps that had to be canceled (there have been more) and also for the team behin CloudFest and it’s hackathon.

With the cancellation of an event, you don’t just stop working. You have to deal with the whole process of canceling any contract and refunding as many people involed as possible. You will also receive some negative feedback from people not understanding the decision (e.g. „there was no case of coron infection in that area“). All organizers involed in those events and the hard decision need our support.

So if you are like me and an event you’ve planed to attend was canceled, take a moment and send a Thank You to the organizing team, as they have made this tough decision in the best interest of the health, both physically and mentally, of our communities. And please support them by attending next years event. Maybe even think about becoming a volunteer. This will give you some first hand experiences on how passionate these organizers are to create these amazing events for all of us.

Thank you event organizers ❤

Repairing image conversation with ImageMagick

Since Version 4.7, WordPress will create a screenshot of the first page of any uploaded PDF file. In order for that to work, ImageMagick and the PHP extension must be installed on the server.

On an Ubuntu 18 webserver I had some WordPress site runnig, the conversion was not working, even though both components were installed. In debugging the issue, I simply tried to do a conversation on the terminal:

convert test-pdf.pdf test-pdf.png

Running the command, I got the following error message:

convert: not authorized `test-pdf.pdf' @ error/constitute.c/ReadImage/412.
convert: no images defined `test-pdf.png' @ error/convert.c/ConvertImageCommand/3210.

After some research I found a solution for the issue. ImageMagick added a security policy some versions ago, which will limit the file types that are allowed to be converted. Unfortunately, the PDF extension is one of those, who can not be converted on Ubuntu 18 by default. But you can simply customize the file /etc/ImageMagick-6/policy.xml which defines the security policies:

<policymap>
  <!-- ... -->
  <policy domain="path" rights="none" pattern="@*" />
  <!-- disable ghostscript format types -->
  <policy domain="coder" rights="none" pattern="PS" />
  <policy domain="coder" rights="none" pattern="EPS" />
  <policy domain="coder" rights="none" pattern="PDF" />
  <policy domain="coder" rights="none" pattern="XPS" />
</policymap>

You can either comment the line with the PDF extension using an XML comment or change the rights to read for PDF:

<policymap>
  <!-- ... -->
  <policy domain="path" rights="none" pattern="@*" />
  <!-- disable ghostscript format types -->
  <policy domain="coder" rights="none" pattern="PS" />
  <policy domain="coder" rights="none" pattern="EPS" />
  <policy domain="coder" rights="read" pattern="PDF" />
  <policy domain="coder" rights="none" pattern="XPS" />
</policymap>

Now you can try again to convert file on the terminal. If the convertion was successful, the comment should not give you any (error) response. If that was successful, upload another PDF into the media library. The screenshot of the first page should now also work there again.

Show missing images from live websites on a development system

When you develop a website, that has already gone live, you usually have to get the latest version of the database to test things. You also need a WordPress system locally with all the plugins and themes that are used on the live website. But how about all the media files that are stored in the uploads folder and that can easily be some gigabytes in size? Well, many times you will need them as well, especially when working on the design. But which ones do you really need locally and how do you keep them up to date with the live website? The good news is: you don’t need to and this blog post will show you an easy way how to solve it differently.

Let’s assume you have just imported a fresh copy of the live database into your local development system. You are probably not seeing some of the files, because as you have updated the URLs in your database to your local domain, those files are not found by the local webserver. You could now connect to the remote server and synchronize the upload folder, potentially downloading many megabytes or gigabyte. If you have multiple projects in development, this will quickly fill up your local hard drive. Or you could just remove the uploads folder alltogether (or at least the uploaded media files in it) and use the files from the live website.

Serve missing files from the live server

For a local environment running on an Apache webserver, you just have to add some lines into your .htaccess files:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^wp-content/uploads/(.*) https://xyz.com/wp-content/uploads/$1 [R=302,L]
</IfModule>

Insert this at the beginning of your .htaccess file and it will do the following.

How it works

The Apache webserver will check, if a file or folder exists locally using two RewriteCond statements. If the file/folder is not found, it will use a RewriteRule for all queries to the wp-content/uploads folder and redirect the query to the domain of your live site.

This will effectively load all images from the remote server. If caching headers are set correctly on the live server, the media files will be downloaded only once.

With this little trick, you can see all the lates media files from the live website without the need to download them. You can even edit them in the media library. Once you save changed being made to a file in the media library, WordPress will store a copy of the live version on the local uploads folder including all other generated images sizes. These changes would not be „synced back“ to the live website, but you can test changes easily on your local environment.

Some caveats

This approach works perfectly for most cases. But it will not work, if a theme or plugin checks, if a file exists on the server. They will usually use some PHP function to check the upload folder, if the required files does exists. As this fix is solved by the webserver, this PHP check would result in a „miss“ of the specfic file.

As most files being checked for existance are usually not stored in the uploads folder, but in folders of the plugins and themes, it should be a huge issue. But in case you ran into such a situation, you have to download the files needed. Finding them might be a bit tricky though.

A second issue is the necessity of a connection to the live webserver. You might work on a website locally, without an internet connection, or a very slow one. While writing this blog post, I’m just taking a train which can result in bad or lost connections. So if you really need the files to work locally, maybe still sychronize some media files.

Does it work for other environments, too?

The same is possible when you use an nginx server in your development environment. But because you usually can not simply add a file to your WordPress document root, you have to add the following lines to your nginx server configuration:

location ~ ^/wp-content/uploads/(.*)$ {
        try_files $uri @missing;
}
location @missing {
	return https://xyz.com$uri;
}

Conclusion

Whenever you make changes to a website, you should work on a local copy. But keeping those copies up to date can be a time and ressource heavy task. In excluding the media files from synchronisations, you can be up running a lot faster and will save a lot of local disk space.

Recude motion on a website for better accessibility

This is my secon blog post in the #FocusAccessibility themed January. Today I want to talk about a topic, that is probably not so common when talking about accessibility. Many of you might know how to optimize websites for visually impaired or blind people. But there are many different types of disabilities. Today I want to hightlight one, that probaly not many of you are aware of.

Motion-triggered vestibular spectrum disorder

The topic is pretty big, although largely unknown. In summary, it means that animations, motions, effects, etc. can harm people viewing a website. I can be a real thread to their health and can lead to epileptic seizure or other symptoms.

Yes, animations and effects are really nice and can make a website even more amazing. But do you really want to harm the visitors of your website? Probably not? But what can you do about it? First of all, get yourself familiar with this issue. There are good articles by Mozilla and A List Apart on that topic. There are also many different elements on your website, that can cause this issue. As I cannot cover all of them, I want to show you a simple way to reduce animations in your CSS code.

The „prefers-reduced-motion“ media query

Fortunately modern browsers and operating systems can help you to improve your website to make it less harmful for those users. You can use the prefers-reduced-motion media query to either wrap all of your animations into it and only play them, when the settings is not set by the visitor of your site. Or you disable animations in this media query. You can find more information about that media query on a blog post by CSS-Tricks.

As an example, you can visit the website of WordCamp Europe 2020. The front page has an animation of the logo. Even though the logo is not an extreme example of harmful animations, there might still users who would prefer to have a static logo.

The Design Team of WordCamp Europe did an amazing job creating this animation with pure HTML and CSS code. But the animation was not wrap into the media query. If the CSS code would be wrapped into it, the animation would not start at all and the logo would not become visible. So how can we easily fix is?

„Fast foward“ the animation

The fix was pretty easy. I just searched for all elements with a CSS animation on it and „fast fowarded“ the animation by setting all delays and durations to zero second, so the logo would be fully visible on page load. The code looks like this:

@media (prefers-reduced-motion: reduce) {
    .wceuicon *,
    .wceuicon:before,
    .wceuicon:after,
    .wceu-logo-text * {
        animation-delay: 0s !important;
        animation-duration: 0s !important;
    }
}

With these few lines, the logo animation is deactivated and the website becomes more accessible.

Reduce the animation

Another solution would be a reduction of the animation. One problematic part of the logo is probably the „blinking cursor“ and the „dots flying in“. We could create an animation, where the dots and the cursor would simply fade in on the designated positions in a slow animation. So we still have an animation, but one with a truely reduced motion.

Test the media query

Now you may wonder how to test the new media query. Many modern operating systems offer options. Mozilla has an overview of the supported browsers and where to find the option in different operating systems. On Google’s Developer platform you also find some more useful tips on the media query and how to test them.

Windows 10

If you use Windows 10, you find the option at „Control Panel | Ease of Access |Ease of Access Center | Make the computer easier to see“:

Just activate the „Turn off all unnecessary animations (when possible)“ checkbox. This setting will not only recude animations in the browser, but in all programs supporting that setting. After you applied the setting, reload the website with the animation. You should now see the optimized/reduces version.

Android 9

I have also found a setting on my mobile phone. Just search for „accessibility“ in the settings. You will then find the switch as „Display | Remove animations“.

There are similar settings on macOS and on iPhones. I was unfortunately not able to find such a settings on my work laptop running on Manjaro linux. But if you know where to find it, please let me know!

Summary

Making a website fully accessible is not an easy task, as many aspects are not as well known as other ones. But when it somes to prioritizing the things to solve first, always start with the things that can harm your visitors. Only then continue with other aspects. I can highly recommend the talk „Prioritizing Accessibility“ by Sarah Brodwall from the last Accessibility Club Summit Berlin.

I hope you have learned a new aspect of accessibility today and I could convice you to use it on your website. If you already have a great reduced animation on one of your sites, please leave a link in the comments, so we can all learn from it.

A few easy steps to make a navigation more accessible

A new year, a new blogging project. Torsten Landsiedel restarted the idea of blogging more regularily. But instead of one blog post per week, he reduced it to one new blog post every two weeks, as well as one comment per two weeks. As I have also participated in previous editions, I will try my best to succeed again. But as this blog is still bilingual, I will post in English in the first week and German in the second week. So I will hopefully post 26 posts, both in English and German.

Focus on Accessibility

Simon Kraft, another long time member of the German WordPress Community, also declared Janurary 2020 to the month with a focus on accessibilty and asks bloggers to focus on that topic. This is why my first two blog posts will have a focus on accessiblity. But probably also some other blog posts this year, as it is a topic I deeply care about.

Accessible navigations

In this first blog post of 2020, I want to show you, how you can easily make your websites navigation more accessible, if it currently is not. The main focus will be on visual and keyboard accessibility.

Improve the visual accessibility

The navigation is maybe the most important element of a website. Both sigthed and visually impaired users will find most sub pages using the navigation. Therefore, the navigation has to be „visually accessible“. Not only for users, but also for assistive technilogies, such as screen readers.

Don’t hide sub menus

When visitors are using a screen reader or similar assistive technology, only elemens that are „visible“ will be announced. If a sub menu is hidden using a CSS rule, than those sub menus are not visible to such a visitor.

Hide them differently

For a classical horizontal top navigation, a typical CSS rule may look like this (example from the Yoko theme from Elmastudio):

#branding #mainnav ul ul {
	display: none;
	float: left;
	position: absolute;
	top: 2em;
	left: 0;
	z-index: 99999;
}
#branding #mainnav ul li:hover > ul {
	display: block;
}

The sub menu is hidden by default. On a hover, the display property is switched to block, so the sub menu becomes visible.

Instead of hiding the element, you could move it out of the viewport, so a sighted visitor cannot see it, but a screen reader can:

#branding #mainnav ul ul {
	display: block;
	opacity: 1;
}
#branding #mainnav ul li:not(.focus):not(:hover) > ul {
	position: absolute;
	left: -999em !important;
	opacity: 0 !important;
}

With this code, we show the sub menu on default. We then move the sub menu out of the viewport and set the opcacity to „invisible“, when the top level menu item is not focused and does not have the CSS class focus applied.

Provide a focus style

In order to make the navigation keyboard accessible, it’s not only imporant, that a user can access all item, it is also important to give a visual feedback on the menu item, the visitor is currently navigating to using the keybord.

Unfortunately, many themes globally remove ony outline property from any element. You can either just set the outline for the navigation item back to the default styles, or you simply use the same styles on focus as you use for the hover state. For Yoko it could look like this:

#branding #mainnav ul li a:focus,
#branding #mainnav ul li a.focus {
	background:#F0F0F0;
	color: #999;
}

We set the styles both for the focus state and CSS class, which will help us with the second step.

Improve the keyboard accessibility

In most navigations, the hover state is used to show a sub menu. When using a website with the keyboard only, this state is not triggered or active in CSS. In order to make a navigation usable using the keyboard tab key only, we use some JavaScript, which will add a CSS class focus, when/while a menu item or one of it’s sub menu items is focused:

( function() {
	var container, menu, links, i, len;
	var navigationContainerId = 'mainnav';
	var menuItemFocusedClass  = 'focus';
	container = document.getElementById( navigationContainerId );
	if ( ! container ) {
		return;
	}
	menu = container.getElementsByTagName( 'ul' )[0];
	if ( -1 === menu.className.indexOf( 'nav-menu' ) ) {
		menu.className += ' nav-menu';
	}
	// Get all the link elements within the menu.
	links = menu.getElementsByTagName( 'a' );
	// Each time a menu link is focused or blurred, toggle focus.
	for ( i = 0, len = links.length; i < len; i++ ) {
		links[i].addEventListener( 'focus', toggleFocus, true );
		links[i].addEventListener( 'blur', toggleFocus, true );
	}
	/**
	 * Sets or removes .focus class on an element.
	 */
	function toggleFocus() {
		var self = this;
		// Move up through the ancestors of the current link until we hit .nav-menu.
		while ( -1 === self.className.indexOf( 'nav-menu' ) ) {
			// On li elements toggle the class .focus.
			if ( 'li' === self.tagName.toLowerCase() ) {
				if ( -1 !== self.className.indexOf( 'focus' ) ) {
					self.className = self.className.replace( ' focus', '' );
				} else {
					self.className += ' focus';
				}
			}
			self = self.parentElement;
		}
	}
} )();

When using this snippet, you can simply set the id attribute of the navigation container and the CSS class that should be added on a focus state in lines 3 and 4. This JavaScript does not even need a library like jQuery and should work with any theme that is using the default WordPress navigations and no other JavaScript enhancements on the navigation. This JavaScript is a slighly modified version of code from the _s theme.

With this JavaScript applied, a visitor can use the keyboard to tab-navigate throught the navigation an all it’s sub menus both forward and backward.

Bonus: Improve the usabilty on tablets

Another issue with a hover state horizontal navigation is the fact, that a mobile device like a tablet does not have a hover. When a visitor would click on any top level item, it would only show the sub menu for a split second, before navigating to this top level item.

We want a top level item with a sub menu to show the sub menu on the first click and only navigate on a second click. For top level items without a sub menu, we want those item to navigate on the first click. This can be done with this additional snippet:

( function() {
	var container;
	var navigationContainerId = 'mainnav';
	var menuItemFocusedClass  = 'focus';
	container = document.getElementById( navigationContainerId );
	if ( ! container ) {
		return;
	}
	( function( container ) {
		var touchStartFn, i,
			parentLink = container.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' );
		if ( 'ontouchstart' in window ) {
			touchStartFn = function( e ) {
				var menuItem = this.parentNode, i;
				if ( ! menuItem.classList.contains( menuItemFocusedClass ) ) {
					e.preventDefault();
					var menuItemLength = menuItem.parentNode.children.length;
					for ( i = 0; i < menuItemLength; ++i ) {
						if ( menuItem === menuItem.parentNode.children[i] ) {
							continue;
						}
						menuItem.parentNode.children[i].classList.remove( menuItemFocusedClass );
					}
					menuItem.classList.add( menuItemFocusedClass );
				} else {
					menuItem.classList.remove( menuItemFocusedClass );
				}
			};
			var parentLinkLength = parentLink.length;
			for ( i = 0; i < parentLinkLength; ++i ) {
				parentLink[i].addEventListener( 'touchstart', touchStartFn, false );
			}
		}
	}( container ) );
} )();

This snippet will use the ontouchstart event to provide the necessary fixes for a drop down navigation on mobile devices.

Conclusing

It is not really hard to make a website’s navigation accessible. You just have to change your CSS a bit and introduce some JavaScript. This is best done in a child theme. You can also provide the fixes to the initial theme developer, so the fix can be provided to all users of the theme. For the Yoko theme in this example, I have created a small plugin, which bundles all the fixes. Just give it a try! Install the Yoko theme and try to keyboard navigate on your page using only the tab key. Then install and activate the plugin and do the same. Also test the navigation on a tablet using your browsers device emulation function.

After that, test your own theme! Is it accessible? Can you easily make it accessible by using the techniques from this blog post? In case your theme is using a „hamburger menu“, take a look on the code from the _s theme, with provides a very user-friendly and accessible way for a mobile navigation with sub menus.