Torgersen Wordpress Theme
- About
- Technologies Used
- Assumptions
- Prerequisites
- Configuration
- Install Node and Bower Packages
- Gulp Build and Watch Commands
- General Sage Documentation
- Accessibility Testing
About
The Torgersen Wordpress Theme is a WordPress theme designed from the ground up to be maximally accessible to people with many different abilities, such as blind/low vision individuals and those with motor or cognitive disabilities. It is made available for use and modification by units at Virginia Tech. It can be downloaded and used as is (must add compiled version as zip eventually) or altered to suit the needs of your particular organization, if you have the technical skills to do so.
Technologies Used
The Torgersen Wordpress Theme uses version 8.5.0 of the Sage starter theme as its base, and is modeled after the Moss template used by Virginia Tech's Ensemble content management system.
Sage uses Gulp as its build system and Bower to manage front-end packages. It uses the official Sass port of Twitter Bootstrap framework as the foundation for its responsive grid-based layout and most of its interactive widgets.
Assumptions
To make changes to this theme, you should have a basic understanding of WordPress theme development generally and the Sage starter theme specifically, the Bootstrap responsive design framework, the CSS extension language, SASS, the NodeJS and Bower package management systems, and the Gulp automation toolkit. Tutorials on many of these topics are available from the Viginia Tech-licensed Lynda training library.
These instructions also assume you have a development instance of Wordpress running with our sample test data loaded into it. Assistive Technologies makes available the Assist Docker Wordpress development environment based on the Visible Wordpress Starter and this comes pre-populated with the test data.
Prerequisites
* Install Phantom JS as per instructions at PhantomJS and Mac OS X . Installing from brew recommended This may no longer be necessary. Must test and update instructions.
- Install node.js. We recommend you update to the latest version of npm:
npm install -g npm@latest
. - Install gulp and Bower globally with
npm install -g gulp bower
Configuration
In the Torgersen theme you've just checked out, locate the file assets/manifest.json and make the following changes to it:
Under paths
, change the value of root
to reflect the full path to the root of the project on your local development environment.
...
"paths": {
"root": "/path/to/torgersen/",
...
}
Note: In the code examples, the elipses, ...
, represents code that has been ommitted from the example.
Update devUrl
to reflect your local development host.
For example, if your local development URL is http://192.168.99.100:8080
you would update the relevant section of the file to read:
...
"config": {
"devUrl": "http://192.168.99.100:8080"
}
...
If your local development URL looks like http://localhost:8888/project-name/
you would update the file to read:
...
"config": {
"devUrl": "http://localhost:8888/project-name/"
}
...
Install Node and Bower Packages
From the project root run:
npm install
bower install
You now have all the necessary dependencies to run the build process.
Gulp Build and Watch Commands
Note: Until you compile your assets with one of these commands, your site will appear broken when loaded in the browser
-
gulp
— Compile and optimize the files in your assets directory -
gulp watch
— Compile assets when file changes are made -
gulp --production
— Compile assets for production (no source maps).
General Sage Documentation
Learn more about how the Sage starter theme works in general by studying its documentation. Remember that currently we are working from version 8.5.0 of Sage; version 9+ handles things differently.
Accessibility Testing
The Torgersen theme is designed to be modified by units on campus to suit their own needs, but has been designed to help ensure that any modifications made to the theme meet the same same high standards for accessibility as the original. To this end, accessibility testing functionality has been integrated into the theme's build system with a couple of gulp tasks:
Possible Workflow
The workflow for using these commands might be something like this:
- Commit changes to your repository, which triggers gulp scan. This basically gives a report that says, "You are committing a file whose filename has matched a defined test suite. We've run scans on the following pages that are built from or use this file, and here are a list of accessibility rules that have been violated." This gives you a quick sense that something is broken.
- To then see that problem in context, you would run gulp scanPage on a particular URL that was flagged in gulp scan. This will load the page in the browser and display a widget that shows the results of scans associated with that page. The user can see all those reports in context on the page that triggered them, and, by clicking on a violation that is listed in a report, have the part of the page that triggered the violation be highlighted.
gulp scan
When the user commits changes to the repository, the gulp scan task is called, running some Mocha tests. These tests work by loading pages in the PhantomJS headless browser and use Selenium's WebDriverJS to dynamically inject the aXe JavaScript accessibility testing library into these pages. aXe will scan specific sections of relevant pages and the results of these tests will be output to the console and will also be published as a web page to test/reports using the MochAwesome reporter.
Exactly what scans get run is determined by the configuration file, test/specs/full.json. Basically, gulp scan will look at each file that has changed in this commit and see if it matches any of the selectors for test suites specified in the configuration file. Each test suite, can be triggered by matching either an exact file name or a regular expression. Suites designed to be triggered based on an exact file name match are stored in the files
array, while suites to be triggered based on a regular expression match are stored in the expressions
array. For each test suite, one or more web pages can be scanned based on page objects defined in the suite
. The options object, describing which accessibility rules will be checked against, and the context object, describing which parts of the page will be examined, are both specified in the conf object associated with the page
. The syntax of the context
and options
objects is based on the aXe Javascript Accessibility API's context parameter, and options parameter, respectively.
File Match Example
In test/specs/full.json, a file test suite may be defined that matches a particular filename, by setting the suite's match
property to the path to that file from the root of the project. For instance, for a particular commit, the file, search.php, may have changed and there may be a suite in the full configuration whose match
property matches that filename.
{
"files": [
{
"match": "search.php",
...
}
]
}
Since search.php is used whenever the home page is accessed with the "s" URL parameter, we will want to create a page
object in that test suite
that matches that URL, so that a scan is run on that page. I know, given the Wordpress unit test data, that a search for "test" will return a list of results, so my first page
object matches the URL with that string as the search query.
{
"files": [
{
"match": "search.php",
"pages": [
{
"match": "/s=test"
...
}
]
}
]
}
However, I also know that search.php returns a different view if my query string doesn't return any results, so I'll need to add a page
object to match that too. In that case, I would set the "s" URL parameter to the garbage string, "kjhgkjhgkj", which I know won't return anything.
{
"files": [
{
"match": "search.php",
"pages": [
{
"match": "/s=test"
...
},
{
"match": "/s=kjhgkjhgkj"
...
}
]
}
]
}
Also, in this case, in order to get the most useful feedback, we will only want to scan the relevant context
, in this case, the part of the page that is generated by search.php, which is contained in the element with the id, "#template-search"
. Similarly, we will not need to run certain tests, such as whether the page has a title, since that is set in the <head>
tag, which is beyond the scope of what search.php affects. Again, what sections of the page to include
and exclude
and what specific rules
to test for is determined by the conf
object.
{
"files": [
{
"match": "search.php",
"pages": [
{
"match": "/s=test",
"conf": {
"context": {
"include": [["#template-search"]]
},
"options": {
"rules": {
"document-title": { "enabled": false },
"meta-refresh": { "enabled": false },
"meta-viewport-large": { "enabled": false },
"meta-viewport": { "enabled": false }
}
}
}
},
...
]
},
...
]
}
For details of how to specify what parts of the page to scan and what rules to include, see the documentation for the axe-core library'scontext parameter and options parameter. Generally, if it can be serialized to a JSON object, you can use the syntax specified there.
Templates
Some configurations will be the same for many scans so, rather than create duplicate conf
objects for all of them, we can create a single template object defining a conf
object common to all of them. Any page
objects that reference that template
will inherit its conf
object properties. Templates are defined in the templates
array in the configuration file. A page
references a template
by setting its template
property to the value of the template's match
property.
Note: The word "template" as used when referring to the template
objects in the templates section of the config file has nothing to do with way the word "template" is used in common Wordpress parlance. They are separate concepts.
As an example, many scans will want to use, as their base, rules tagged as being associated with "WCAG 2.0 A", "WCAG 2.0 AA", and "Best Practice". We can create a template called "base" that defines these base rules that are to be used and have our page
object reference that.
Base Template
{
"files": [
...
],
"templates": [
{
"match": "base",
"conf": {
"options": {
"runOnly": {
"type": "tag",
"values": ["wcag2a", "wcag2aa", "best-practice"]
}
}
}
}
]
}
Page That References Template
{
"files": [
{
"match": "templates/footer.php",
"pages": [
{
"match": "/",
"template": "base",
"conf": {
"context": {
"include": [["footer#vt_footer_wrapper"]]
},
"rules": {
"document-title": { "enabled": false }
}
}
}
]
}
],
"templates": [
...
]
}
In our example, we still have a conf
object associated with the page
object, even though that page
object is also referencing the template
. In this case, the conf
object contained in the page
object supplements the conf
object in the template
, by specifying that the "document-title" rule is to be excluded from the scan. It also limits the context
so that only the contents of our page's primary footer tag will be scanned.
Templates matching templates
page
objects can reference template
objects, but template
objects can also reference other template
objects, inheriting properties from them. Knowing this, we could eliminate the conf
object from the page
object altogether and just reference a "footer" template
object, which in turn inherits from the "base" template
.
{
"files": [
...
"match": "templates/footer.php",
"pages": [
{
"match": "/",
"template": "footer"
},
...
]
]
"templates": [
{
"match": "footer",
"template": "base",
"conf": {
"context": {
"include": [["footer#vt_footer_wrapper"]]
},
"rules": {
"document-title": { "enabled": false }
}
}
},
{
"match": "base",
"conf": {
"options": {
"runOnly": {
"type": "tag",
"values": ["wcag2a", "wcag2aa", "best-practice"]
}
}
}
}
]
}
Regular Expression Match Example
In our previous examples, we showed how a suite of tests can be triggered by a filename match, but you can also use a regular expression to trigger a match. For instance, you can write a regular expression that matches any file ending in "scss", "/^(?!\\.\\.\\/).*\\.scss$/i"
, and any time one of those files change, you can scan a representative sample of pages using a template that looks at the whole page, but only tests rules that would be affected by styling changes, such as "color-contrast".
{
"expressions": [
{
"match": "/^(?!\\.\\.\\/).*\\.scss$/i",
"pages": [
{
"match": "/about/page-markup-and-formatting/",
"template": "scss"
}
]
}
],
"templates": [
{
"match": "scss",
"conf": {
"options": {
"runOnly": {
"type": "rule",
"values": ["button-name", "color-contrast", "link-in-text-block", "link-name"]
}
}
}
}
]
}
Setting Regular Expression Suites to Only Run Once
Depending on your purposes, for a particular set of file names in a commit, you may want a regular expression suite to only be run the first time a file in that set is matched, or every time. This option is set using the once
property in the regular expression suite
. So, for instance, if you wanted to run a suite of tests of JavaScript-related functionality only once, even if there were multiple JavaScript files in your changeset, you would set once
to the boolean value true
, like so:
{
"match": "/^(assets\\/scripts\\/).*\\.js$/i",
"once": true,
"pages": [
{
"match": "/",
"template": "js"
}
]
}
The default value for once
is false
, so, unless otherwise specified, a regular expression suite will be run every time it is matched. File suites, by contrast, do not have a once
property and are always run only once.
gulp scanPage
In addition to running scans automatically based on files that have changed since the last commit to the master branch, the user can choose to run a scan on a particular page using the gulp scanPage
command passing in the match
parameter for the page to be scanned. So, to scan the home page, you would run the following:
gulp scanPage --match=/
Running this type of scan looks through all the suites
in the full config file for any page
objects whose match
property is the URL referenced and, for each one, runs a scan based on its associated conf
object. Thus, several separate scans may be performed on a single page, each taken from a separate suite
. For instance, there may be one that scans the footer with a certain set of rules, one that scans the header with a different set of rules, and so forth. When this type of scan is run, the specified URL is opened in the browser and the results displayed as plugins of the tota11y accessibility visualization toolkit, a collapsible widget that is injected into the page.