Elasticsearch, Isomorphic JavaScript, Presentations, Search

ZendCon 2017

I'm excited to once again be presenting at ZendCon 2017. This year I'll be doing two talks.

On Tuesday, October 24, I'll be presenting "Isomorphic WordPress Applications using NodeifyWP" which will cover isomorphic JavaScript in WordPress, specifically NodifyWP, Twenty Sixteen React, and the NodifyWP Environment. Here are my slides.

On Thursday, October 26, I’ll be presenting “Transforming WordPress Search and Query Performance with Elasticsearch “. This talk will cover Elasticsearch, ElasticPress and WordPress. Here are my slides:

Standard
Isomorphic JavaScript, JavaScript, Node.js

Isomorphic WordPress Applications using NodeifyWP at WordCamp Lancaster 2017

This weekend I'll be presenting on "Isomorphic WordPress Applications using NodeifyWP". I'll also be discussing the NodeifyWP Environment – a Dockerized environment pre-setup for running NodeifyWP applications.

Standard
Presentations

WordPress Best Practices for Enterprise at Music City Code

Today I'm presenting on Best Practices for WordPress in Enterprise at Music City Code 2016. Here are a few of the topics that will be covered:

  • – Caching for high traffic situation
  • – Security techniques
  • – Writing maintainable/extensible code
  • – Optimizing database reads/writes
  • – Search
  • Teamwork in software development
  • – Browser performance
  • – Workflows
  • – Utilizing third party libraries

Slides for anyone who needs them:

This presentation is based on 10up’s amazing Best Practices.

Standard
WooCommerce, WordPress Code Techniques, WordPress Core

post_class() and get_post_class() – Performance Killers for WordPress and WooCommerce

The get_post_class() function is a WordPress function commonly used within post “rivers”. For example, if I had a list of posts, WooCommerce products, or any content type really, I might have some code like this:



<div >

Note: post_class() just calls get_post_class() and outputs it to the browser.

post_class() will output something like class="post has-post-thumbnail type-POST-TYPE status-POST_STATUS tag-TAG1 tag-TAG2 category-CATEGORY1 category-CATEGORY2 ...."

The classes added make it easy to style content that has a specific taxonomy term, has a thumbnail, a particular status, etc.

However, the queries needed to determine all this information are not cheap. Moreover, this function is probably called for every post you’re listing. So if you have posts_per_page set to 20, this function will be called 20 times.

Let’s take a look at the function’s code (I’ve trimmed some of the comments):

function get_post_class( $class = '', $post_id = null ) {
	$post = get_post( $post_id );

	$classes = array();

	if ( $class ) {
		if ( ! is_array( $class ) ) {
			$class = preg_split( '#s+#', $class );
		}
		$classes = array_map( 'esc_attr', $class );
	} else {
		// Ensure that we always coerce class to being an array.
		$class = array();
	}

	if ( ! $post ) {
		return $classes;
	}

	$classes[] = 'post-' . $post->ID;
	if ( ! is_admin() )
		$classes[] = $post->post_type;
	$classes[] = 'type-' . $post->post_type;
	$classes[] = 'status-' . $post->post_status;

	// Post Format
	if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
		$post_format = get_post_format( $post->ID );

		if ( $post_format && !is_wp_error($post_format) )
			$classes[] = 'format-' . sanitize_html_class( $post_format );
		else
			$classes[] = 'format-standard';
	}

	$post_password_required = post_password_required( $post->ID );

	// Post requires password.
	if ( $post_password_required ) {
		$classes[] = 'post-password-required';
	} elseif ( ! empty( $post->post_password ) ) {
		$classes[] = 'post-password-protected';
	}

	// Post thumbnails.
	if ( current_theme_supports( 'post-thumbnails' ) && has_post_thumbnail( $post->ID ) && ! is_attachment( $post ) && ! $post_password_required ) {
		$classes[] = 'has-post-thumbnail';
	}

	// sticky for Sticky Posts
	if ( is_sticky( $post->ID ) ) {
		if ( is_home() && ! is_paged() ) {
			$classes[] = 'sticky';
		} elseif ( is_admin() ) {
			$classes[] = 'status-sticky';
		}
	}

	// hentry for hAtom compliance
	$classes[] = 'hentry';

	// All public taxonomies
	$taxonomies = get_taxonomies( array( 'public' => true ) );
	foreach ( (array) $taxonomies as $taxonomy ) {
		if ( is_object_in_taxonomy( $post->post_type, $taxonomy ) ) {
			foreach ( (array) get_the_terms( $post->ID, $taxonomy ) as $term ) {
				if ( empty( $term->slug ) ) {
					continue;
				}

				$term_class = sanitize_html_class( $term->slug, $term->term_id );
				if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) {
					$term_class = $term->term_id;
				}

				// 'post_tag' uses the 'tag' prefix for backward compatibility.
				if ( 'post_tag' == $taxonomy ) {
					$classes[] = 'tag-' . $term_class;
				} else {
					$classes[] = sanitize_html_class( $taxonomy . '-' . $term_class, $taxonomy . '-' . $term->term_id );
				}
			}
		}
	}

	$classes = array_map( 'esc_attr', $classes );

	$classes = apply_filters( 'post_class', $classes, $class, $post->ID );

	return array_unique( $classes );
}

Within this code, the following functions might result in database queries: get_post_format, has_post_thumbnail, is_sticky, and get_the_terms. The most expensive of these queries is get_the_terms which for each taxonomy associated with the post type, selects all the terms attached to the post for that taxonomy. If there are four taxonomies associated with the post type being queried, get_post_class could result in 7 extra database queries per post. With 20 posts per page, that’s an extra 140 queries per page load! On WooCommerce sites where there are many taxonomies and usually many products per page being shown, this is a huge performance killer. Yes, object caching (and page caching of course) will improve our eliminate some of the database queries, but people will still be hitting the cache cold sometimes.

Solution:

Don’t use get_post_class or post_class. It’s not that important. 99% of people don’t use the tags it generates. What I do is output the function, inspect the classes it adds using Chrome, and hardcode the classes actually referenced in CSS into the theme.

PS: body_class() is much less query intensive and okay to use.

Standard