WordCamp Talk: Life-Changing Design and Development

Standard

Check out my talk from WordCamp Kansas City on June 28, 2019. I’d love to know what you think!

Synopsis:
In this talk, we’ll discuss how our decisions as designers and developers affect people’s lives, as well as practical ways our daily work can actually change the lives of others for good. If we really believe that WordPress is about democratizing publishing — empowering anyone to share their voice with the world — then our work must always reflect that value. This means that our creations must be accessible to those with differing levels of physical abilities, as well as those with differing levels of experience and those who speak other languages. Citing real-life examples, we’ll learn to think differently about building WordPress and look at practical ways to implement this in our daily work.

How to Improve WordPress Load Times Using Transients

WordPress Transients Tutorial
Standard

WordPress load times can be a serious concern if you’re working with a complicated page that has a lot of queries or API calls.

I’ve worked with several enterprise publishing sites, and site speed was always a concern because of the complex features that fill the page: related news, latest posts from several categories, news tickers, social media feeds, etc.

Loading so many features is a concern because hitting the database so many times so quickly can be a burden on the server, and when you factor in the limited number of API calls many services allow, we need a solution to store data for a brief period of time.

WordPress Transients

Enter WordPress transients.

Transients save information to the database for quick access. These are also nice because they can expire after a limited time, meaning that fresh data can be fetched based on time intervals.

The best part is they’re easy to use.

They work a lot like options or post meta in WordPress. It’s a simple function that takes a name, a value, and an optional expiration time.

Here’s how they work:

First, you check to see if anything is stored in the transient.

$value = get_transient( 'jr3_transient' );

If the desired data is not there, get your data and store it in the transient.

$value = jr3_get_data();
set_transient( 'jr3_transient', $value );

The nice thing is that you can set an expiration time for the transient. This means that if you need to only store the data temporarily, even if it’s just a few seconds, you can do that by adding the third parameter to the function.

// Store for 5 minutes.
set_transient( 'jr3_transient', $value, 5 * MINUTE_IN_SECONDS );

Here’s a more fully-featured example:

<?php
/**
* Get News posts.
*
* This is from a tutorial found here:
* @link https://johnregan3.wordpress.com/how-to-improve-wordpress-load-times-using-transients
*
* @since 1.0.0
* @uses jr3_news_query
*
* @return array Array of news posts, else an empty array.
*/
function jr3_get_news() {
$output = get_transient( 'jr3_news' );
/*
* Side note:
* When an empty array is possible
* (like if a stored array of posts is empty because
* none were found), don't do the typical "! empty()" check.
*
* If the transient is not found, it will return false.
*/
if ( ( false !== $output ) && ( is_array( $output ) ) ) {
// Return the array stored in the transient.
return $output;
}
// Imaginary function to fetch data.
$results = jr3_news_query();
if ( is_array( $results ) ) {
// Set our transient to expire in one hour.
set_transient( 'jr3_news', $results, HOUR_IN_SECONDS );
return $results;
}
// At a minimum, return an empty array.
return array();
}

Advanced Transient Names

It’s possible that you want to store the transient name based on the post being viewed, as may be the case if you are storing data for posts related to the present post. You can do this by adding the post ID to the transient name:

$transient_name = 'jr3_transient_' . get_the_ID();
$value = jr3_get_data();
set_transient( $transient_name, $value );

Super-Advanced Transient Names

It’s important to note that transient names are limited to 191 characters. This can be an issue when storing a specific WP_Query call. I run into this when I’m doing taxonomy queries, which are notoriously slow. In order to save this data in a transient name, I actually use the query arguments to generate the transient name.

Let’s say this is our query:

$wp_query_args = array(
'post_type' => 'book',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'genre',
'fields' => 'slug',
'terms' => $genre_array,
),
array(
'taxonomy' => 'publisher',
'fields' => 'slug',
'terms' => $publisher_array,
),
),
);

Since we don’t know for sure what the $genre_array and $publisher_array will hold, we can’t hard-code a static transient name.

To solve this, we’ll use the actual $wp_query_args array to generate the transient name. We do this using two methods.

First, we turn the array into a string format using maybe_serialize(), but this still leaves us with the issue of running into the 191-character limit on the transient name.

Second, to handily convert this potentially long serialized string into a shorter string, we convert it into an MD5 hash, which turns our long string into a 32-character string, allowing us room to prefix it.

$transient_name = 'jr3_' . md5( maybe_serialize( $wp_query_args ) );

This allows us to do something like this, ensuring that this specific query will be stored in the transient:

<?php
/**
* Get Books posts.
*
* This is from a tutorial found here:
* @link https://johnregan3.wordpress.com/how-to-improve-wordpress-load-times-using-transients
*
* @since 1.0.0
*
* @param array $genre_array An array of genre slugs.
* @param array $publisher_array An array of publisher slugs.
*
* @return array Array of books, else an empty array.
*/
function jr3_get_books( $genre_array, $publisher_array ) {
/*
* For the sake of this tutorial, we'll assume
* $genre_array and $publisher_array are valid arrays.
*/
$wp_query_args = array(
'post_type' => 'book',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'genre',
'field' => 'slug',
'terms' => $genre_array,
),
array(
'taxonomy' => 'publisher',
'field' => 'slug',
'terms' => $publisher_array,
),
),
);
// Generate the transient name.
$transient_name = 'jr3_' . md5( maybe_serialize( $wp_query_args ) );
$books = get_transient( $transient_name );
if ( ( false === $books ) || ( ! is_array( $books ) ) ) {
$books = array();
// Run the Query.
$query = new WP_Query( $wp_query_args );
if ( is_array( $query->posts ) ) {
// Rename for output.
$books = $query->posts;
// Set our transient using our generated name.
set_transient( $transient_name, $books, HOUR_IN_SECONDS );
}
}
return $books;
}

Conclusion

If you are working on a site with lots of queries, you really should be using transients. They are extremely hand for temporarily storing data, whether it be an array of posts, or the results of an API call (like fetching recent tweets). They are easy-to-use, and can be set up in just a few minutes.

Further Reading

How To Add Custom Editor Styles to Gutenberg

Standard

Adding Custom Gutenberg editor styles in WordPress is a nice touch to any theme, as it allows authors to get a basic preview of their content before it gets published. It seems like a complicated task, but it’s actually pretty simple, once you get started.

Before

Default Gutenberg Editor Styles

After

Custom Gutenberg Editor Styles

The PHP

It begins with registering and enqueueing a CSS file in your theme.

<?php
/**
* Enqueue the Gutenberg editor stylesheet.
*
* Put this in your functions.php.
*
* @action enqueue_block_editor_assets
*/
function jr3_enqueue_gutenberg() {
// Make sure you link this to your actual file.
wp_register_style( 'jr3-gutenberg', get_stylesheet_directory_uri() . '/css/editor.css' );
wp_enqueue_style( 'jr3-gutenberg' );
// This font is enqueued for the demo only. You probably won't need this.
wp_register_style( 'jr3-webfonts', 'https://fonts.googleapis.com/css?family=Montserrat&#39; );
wp_enqueue_style( 'jr3-webfonts' );
}
add_action( 'enqueue_block_editor_assets', 'jr3_enqueue_gutenberg' );

The CSS

The CSS is a bit trickier because there are so many blocks and elements to cover. Here is an example that I’ve put together for this demo that can be a starting place for you.

/* Custom Editor Styles */
/*
* With some edits, this can be used as a base for your Custom Editor Styles.
* Note that this is for demonstration purposes only, and some elements may not
* be covered here.
*/
/* Approximate the theme width, except for full-width images. */
.wp-block:not( '.editor-block-list__block["data=full"]' ) {
width: 95%;
max-width: 1000px;
}
/* Fonts */
/* Note that Montserrat is enqueued in the PHP function that enqueues this file */
.editor-writing-flow .wp-block textarea,
.editor-writing-flow .wp-block .wp-block-freeform,
.editor-rich-text p,
.editor-post-title__input,
.wp-block-quote__citation {
font-family: 'Montserrat', Arial, Helvetica, sans-serif;
}
/* TinyMCE Editor */
.editor-styles-wrapper p,
.editor-rich-text p,
.editor-styles-wrapper blockquote {
font-size: 16px;
line-height: 22px !important;
}
.editor-writing-flow .wp-block a {
color: #00a2ad !important;
}
/* Headings */
.editor-writing-flow .wp-block h1,
.editor-writing-flow .wp-block h3,
.editor-writing-flow .wp-block h3{
font-weight: bold;
}
.editor-writing-flow .wp-block h1 {
font-size: 36px;
line-height: 1.5em;
}
.editor-writing-flow .wp-block h2 {
font-size: 25px;
line-height: 1.5em;
}
.editor-writing-flow .wp-block h3 {
font-size: 16px;
line-height: 1.5em;
}
/* The Post Title */
.editor-post-title__block .editor-post-title__input {
color: #00a2ad;
text-align: center;
}
/* Blockquote styles */
.wp-block blockquote {
font-style: italic;
color: #aaa;
margin-left: 20px;
border-left: 0;
padding-left: 0;
}
.wp-block blockquote .editor-rich-text {
padding-left: 3rem;
}
.wp-block blockquote:before {
color: #ccc;
content: '\201C' !important;
font-size: 4em;
position: absolute;
top: 10px;
}
.wp-block-quote:not(.is-large):not(.is-style-large) {
border-left: 0;
margin-left: 0;
padding-left: 0;
}

How to Add Full Width Images in Gutenberg

Theme Preview with a Full-Width Image
Standard

Full width images are a sweet new feature that Gutenberg offers to WordPress theme developers. In order to enable these in your theme, it takes just a few lines of code.

Problem #1

By default, the Gutenberg Image Block only has the three classic alignment options: left-aligned, centered, and right-aligned.

Gutenberg Default Image Alignment Options
Gutenberg Default Image Alignment Options

Enabling Wide Images in the Gutenberg Editor

First, a bit of PHP.  Add this to your theme’s functions.php, or wherever else you are adding your add_theme_support() functions.

<?php
/**
* Add Theme Support for wide and full-width images.
*
* Add this to your theme's functions.php, or wherever else
* you are adding your add_theme_support() functions.
*
* @action after_setup_theme
*/
function jr3_theme_setup() {
add_theme_support( 'align-wide' );
}
add_action( 'after_setup_theme', 'jr3_theme_setup' );

Now, you can find two new icons on your Image Gutenberg Block, wide-align, and full-width.

Gutenberg Image Block Updated Options

When one of these options is selected, it will display correctly in the editor.  If you select wide-align, the image gets wider, and if you select full-width, the image fills the editor horizontally.

Wide Image Previews in the Gutenberg Editor

Gutenberg Image Block Wide Width in the Editor
A wide image in the Gutenberg Editor
Gutenberg Image Block Full Width in the Editor
A full-width image in the Gutenberg Editor

Problem #2

There’s just one issue: Although WordPress adds special classes to the image markup, this doesn’t affect your actual theme styles.

Gutenberg Image in the Theme, unstyled
An unstyled full-width image in the Theme.

The Solution

To solve this, add your own CSS.  Here’s a snippet I came up with:

.alignwide {
/* Set these margins to work with your own theme. */
margin-left: -80px;
margin-right: -80px;
max-width: 100vw;
}
.alignfull {
margin-left: calc(-100vw / 2 + 100% / 2);
margin-right: calc(-100vw / 2 + 100% / 2);
max-width: 100vw;
}
.alignfull img {
width: 100vw;
}

A few notes about the CSS:

  • calc() tells the browser to calculate a value (usually) based on the screen size.
  • vw refers to “viewport width,” or screen width.

The Result

After the styles are applied:

Gutenberg Wide Image in the Theme
A wide-aligned image in the theme after adding the CSS.
A full-width image in the theme after adding the CSS.
A full-width image in the theme after adding the CSS.

So, with less than 20 lines of code, you can add this powerful and attractive feature to your themes.

Further Reading

Simple Custom CSS Version 4.0 Released

Standard

After nearly 2 years, I’m proud to announce that Simple Custom CSS has received a big upgrade!

Background

I was fortunate enough to work on the first iteration of the WP Customize Code Editor Control and associated “Additional CSS” Customizer section released in WP version 4.7.  It was a huge learning experience, and my first major contribution to WP Core.

I’ve taken the lessons learned during that release to bring you a completely updated version of Simple Custom CSS!

The Customizer

screenshot-2aI’ve updated Simple Custom CSS to now use the Customizer, allowing live previews of your CSS before you save any changes.

I’ve styled the WP_Customize_Code_Editor_Control to give a similiar experience to the Core “Additional CSS” section, meaning that the editor is full width/height so that you have more room to view your code than the default display of the edtor.  And, just like Core, this supports CSSLint.

The Settings Page

screenshot-1
The Simple Custom CSS Settings Page
CSS Linting in Simple Custom CSS
CSS Linting

The Settings page now supports CSSLint, which means that it will clearly point out syntax errors.  I’ve also modified the colors there to show more contrast, and to more closely match the core WP CodeMirror styles.

I’ve also updated the packaged CodeMirror to the latest versions.  These hadn’t been updated in nearly 4 years.

The Future

There are a few features I’d like to build out in the future, including support for Sass and LESS.  I have some ideas on how to do this thanks to Weston Ruter’s WP Custom CSS Demo Plugin.

Eventually, I’m going to remove the plugin’s packaged CodeMirror scripts.   WP core now includes the same CodeMirror scripts that have been used in the Simple Custom CSS settings page, but I’ve kept the plugin’s packaged CodeMirror JS just in case you’re running an older version of WP that doesn’t yet have CodeMirror support.

I also want to move the Customizer code to JS.  I’ve seen a lot of others use Simple Custom CSS as a base for their plugins and theme tools (which I think is great!) and I want to keep it in PHP for a while so other developers can better follow how I’ve set it all up.  I hope this will lead to more widespread adoption of the Code Editor Control.

Much further down the road, I want to remove the Settings page altogether.  I’d like to see wider adoption of the Customizer for settings, plus at this point for the plugin it has become redundant to maintain both editors.  When I do that, I’ll be sure to notify everyone in advance, and perhaps just point the “Appearance > Custom CSS” link to the Customizer Section directly.  I’d love your feedback on this.

Thank You!

sccss-v1
v1.0 of Simple Custom CSS

I built this plugin out of personal need back in August 2013, and at the time I had no idea how much of a help it would be to others in the WP Community.

It’s thanks to you that Simple Custom CSS has come so far!  Your feedback and support have been so encouraging to me over the years, and I love having a way to give back to the Community that has given me so much.

I hope this update will make the plugin even more useful to you and give you a more powerful editing experience.

Here’s to many more years of Simple Custom CSS!