Viewing WordPress View all News

Should I Update WordPress 5.0 and the New Gutenberg Editor?

WordPress logo

WordPress announced TODAY that they would be releasing WordPress 5.0, a major update to their platform (view information on WordPress 5.0 Gutenberg.)

Although the ability to utilize 5.0 as a Beta has been around for a minute, every WordPress site now has a large “Update Your Site to 5.0.” The main question is, should you update now and what you need to be concerned with.

What is WordPress 5.0

WordPress 5.0 is a major release to the WordPress CMS. It has been in the works for some time and was released December 6, 2018 with almost no notice to digital agencies that utilize WordPress and hundreds of thousands of companies who utilize WordPress as their CMS.

WordPress 5.0 Call To Action

Should You Update to WordPress 5.0

There is a lot to consider before updating. How many plug-ins do you use? How much of your site is tied to custom plug-ins, or 3rd party technologies? Have those technologies updated to be compliant with 5.0.

A good example of this is Advanced Custom Fields, a plug-in used by MANY WordPress developers.

Here is what you see as of this morning. 100% compatibility with WordPress 4.9.8. and Unknown for 5.0.

Advanced Custom Fields

Personally, BBG considers this an issue and would not update a site until that says 100%. WordPress sites could utilize many plug-ins, so checking into every single one and every single technology connection is important before making this update.

Back-Up Your Site!

Before you update to WordPress 5.0 create a back-up of your site. This is critical. Your digital ecosystem is comprised of the WordPress CMS as well as connections to external sources and external sources talking to your CMS. You want to make sure that all of these work.

Our Recommendation Is To Wait

As this is new TODAY, BBG recommends waiting on updating your site. Plenty of early adopters will find bugs, transitional issues, non-compatible plug-ins and there will be a scramble to fix over the next few months. Let that happen before you update.

If You Need Help With This Update, or Help Understanding Gutenberg Reach Out

Feel free to contact Bright Bright Great. Happy to help!

Posted By
Jason Schwartz

New Work: Celebrating 100 Years of Color with Rit Dye

For over 100 years, Rit Dye has been on a mission to deliver enduringly beautiful color to our most loved fabrics. Introduced in 1918, 2018 marks Rit’s 100 year anniversary and also marks the launch of their new digital experience and digital tools for every dyeing process.

Rit Dye Logo Rit Dye Website Rit Dye IconographyRit Dye Website Mobile Rit Dye Website MobileRit Dye Website

The BBG team also had the amazing opportunity to shoot with Barbie Roadkill for the Rit Site in her home studio.

Rit Dye Photography Rit Dye PhotographyRit Dye Barbie Roadkill Rit Dye Barbie Roadkill Rit Dye Barbie Roadkill Rit Dye Barbie Roadkill Rit Dye Rit Dye Photography Rit Dye Photography

Learn more about Rit Dye and their 100 years of dyeing https://www.ritdye.com/

(Before shot for posterity)

Rit Dye 2017

Posted By
Jason Schwartz

New Work: The Landing Hotel, Rivers Casino Hotel Experience

Bright Bright Great is excited to announce the launch of branding and in-hotel experience for The Landing Hotel, an upscale boutique destination with 165 rooms situated on the picturesque Mohawk Harbor in Schenectady, New York, with direct access to the Rivers Casino & Resort.

Bright Bright Great has been working with Rush Street (Rivers Casino & Resort & SugarHouse Casino’s parent company) since 2015 on multiple projects in branding, digital/web and print. The Landing Hotel branding is the first BBG project to launch live, with a new Rush Street digital experience launching later this month.

This project uses Avondale Type Co.‘s sans serif font ATC Arquette, a typeface designed in-house, which is not only used for the physical signage for the hotel, but also throughout the brand.

Posted By
Jason Schwartz

New Work: Strata, a Comcast Company

Bright Bright Great is excited to announce the launch of the new Strata website, a Comcast company that processes 25% of the total U.S. ad spend ($60+ billion dollars of advertising.)

Bright Bright Great worked with Strata starting initially with digital strategy, art direction and seeing the project come to fruition with content strategy as Strata overhauled a dated and limited brand.

Strata, which is a Comcast company, processes 25% of the entire total U.S. ad spend annually (currently of $65 billion dollars)! Yes, you read that right, $65 billion+ in ad spend.

“…Always an adventure! A true collaboration with the best partners and colleagues in design…”

— Judd Rubin, SVP Revenue and Marketing

 

 

Bright Bright Great also worked with our friends Pentagram in NYC on branding for this project. A major thank you to Eddie Opara and his team for additional support on this project.

This project also uses Avondale Type Co.‘s sans serif font ATC Arquette, a typeface designed in-house, which has been selected by Comcast as the corporate typeface for the Strata brand.

Posted By
Jason Schwartz

WordPress Static Page Cache

WordPress is a dynamic application. When a page is requested, the application loads hundreds or thousands of files into memory, makes dozens or hundreds of database queries, and eventually, crafts a static HTML document, which the visitor’s web browser can then render as a web page.

All of this happens every time someone pulls up a web page.

As you might imagine, the complexity of such operations can put quite a strain on humble web servers. As traffic levels increase, the struggle to meet the demands can result in WordPress sites slowing to a crawl or worse, crashing.

Investments in better hardware will postpone the inevitable, but to really address the problem head on, one must eliminate the dynamic nature of WordPress.

By saving a static copy of the page being generated to the server, the chain of events must only occur once; after that, the server need only hand over the ready-made page when visitors request it.

This is the perfect solution for content-driven web sites like blogs and portfolios. When changes are made to the database (e.g. a new post is published, or an old one is edited), the author can simply clear the cache and the site is good as new!

This solution is not so good for interactive user sites like stores and forums, where access to realtime data or personalized templates are required. At the end of this article, we’ll examine some tricks that might still offer assistance for these types of sites.

W3 Total Cache

There are a lot of caching plugins available to WordPress, but none are as comprehensive as W3TC. It is available in both free and premium versions, however for users looking at just the static page caching functionality, the free version will suffice.

First things first, install it.

Once activated, you’ll find a “Performance” tab in the admin menu. Go to “Performance” > “General Settings” to enable page cache (to disk). Now go to “Performance” > “Page Cache” to configure settings specific to page caching. For most sites, the default settings will suffice. If you have any pages that need to be served dynamically, such as a contact form or a page displaying randomized content, you can add it to the list of “Never cache the following pages”.

That’s it!

You can verify page cache is working by looking at the source code of a page on your site. You should see something like the following at the end:

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/
Page Caching using disk: enhanced
Served from: brightbrightgreat.com @ 2015-07-11 10:17:07 by W3 Total Cache -->

If page cache is disabled for logged in users, you might instead see:


<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/
Page Caching using disk: enhanced (User is logged in)
Served from: brightbrightgreat.com @ 2015-07-11 11:14:21 by W3 Total Cache -->

The (User is logged in) lets you know that page cache would be used, were it not for the fact that logged in users are specifically excluded from it.

W3TC has a lot of features beyond page cache that are worth checking out. “Minify” will attempt to compress static documents before saving them to disk, which can result in faster load times for users.

Minification can break things in unexpected ways, so if you enable it, carefully double-check that your site is still working as expected (you can use an Incognito/Private session to view the site as a regular visitor would see it without having to log out of your account). If your server is already gzipping requests, you probably won’t see substantial performance gains from Minify.

To completely clear your static page cache, click “Performance” > “Empty All Caches” in the admin toolbar. If you forget to do this, the cache will empty itself automatically eventually.

Advanced

The biggest disadvantage to using static page cache is that pages are, well, cached. If a web site allows users to log in and then shows them personalized content (e.g. “Welcome back, Jane!”), static page cache won’t work correctly; all visitors will receive the same static page. Either Jane won’t see her message, or everyone will see Jane’s message.

One possible workaround is to disable cache for logged in users, but allow it for everyone else. If your site users are simply low-privilege WordPress users (e.g. subscribers), this is the default behavior anyway. But cache can also be disabled by the presence of a cookie; if user sessions are controlled through custom code, set a cookie at login (and remove it at logout), and add the cookie name to “Rejected cookies” list.

For sites where the session-specific variation is minimal, it might be preferable to maintain static page cache for all users, and let Javascript make any necessary adjustments at runtime.

A good example of this would be a storefront that displays the current cart count in the toolbar. As items are added to the cart, the count could be written to a cookie, which Javascript could then read and plop into place. Highly specific pages like the shopping cart could be individually excluded from cache, ensuring they are always up-to-date.

Lastly, it might be necessary for sites to clear the page cache programmatically. For example, if a product page lists its availability, that figure should be adjusted when a new order is placed.

To do this, make a wrapper function like the following (add/remove caches as necessary), and include calls to it where needed:

function my_cache_clear(){
	//clear W3TC page cache
	if(function_exists('w3tc_pgcache_flush'))
		w3tc_pgcache_flush();

	//clear W3TC database cache (comment out if not using)
	if(function_exists('w3tc_dbcache_flush'))
		w3tc_dbcache_flush();

	//clear W3TC object cache
	if(function_exists('w3tc_objectcache_flush'))
		w3tc_objectcache_flush();

	//clear W3TC minify cache
	if(function_exists('w3tc_minify_flush'))
		w3tc_minify_flush();
}

These techniques are no substitute for good coding and asset optimization, but they can give your site a boost and help make sure pages load quickly and efficiently.

Posted By
Josh Stoik

How to Log MySQL Errors in WordPress

MySQL query errors can be difficult to diagnose and correct.

For performance reasons, most MySQL installations fail to retain an error log for posterity; instead, if an error occurs, the reason is passed back to the application during runtime. If that error isn’t captured then and there, it is lost forever.

Development Environments

WordPress contains a special development mode that can be enabled by adding WP_DEBUG, WP_DEBUG_LOG, and/or WP_DEBUG_DISPLAY constants to your configuration. When enabled, PHP errors/warnings/notices and MySQL errors will be logged to wp-content/debug.log and/or printed to the screen.

WordPress’s $wpdb object also provides some debugging functions in case you wanted to debug MySQL issues independently of PHP ones:

  1. $wpdb->show_errors(): this causes MySQL error information to be printed to the screen as it happens. You would call this function before the queries you are looking to debug.
  2. $wpdb->hide_errors(): this reverses the behavior of show_errors() and returns WordPress to its default configuration. You can call this function anytime after executing the questionable queries.
  3. $wpdb->print_error(): this prints the error, if any, from the most recent query.

Production Environments

These tools are probably all you need when developing a new theme or plugin, but you shouldn’t use these under production environments. For one thing, printing random, technical-looking strings in the middle of a document will break the layout and confuse your users. It can also provide interesting information to any bad actors who might be poking around your site. But even if you’re just logging the information, WP_DEBUG_LOG isn’t a great idea: it degrades your site performance and, under most server configurations, exposes way too much information to anyone who knows where to look.

Of course, by the time a site is live, you should have thoroughly debugged everything, so there’s no need to log query failures, right? Well… maybe.

There are a lot of ways to mess up a MySQL query. Chances are, no matter how many times you tested your code during development, you’ll have missed some highly obscure edge case. Even if you didn’t, and everything was coded perfectly, sometimes an update to the WordPress core can subtly change the way a query is structured.

Such a change occurred recently with the release of WordPress 4.4. In prior versions, Null values passed via $wpdb->insert() or the like were typecast according to the type specified. %s would convert a Null value to '', %d to 0, etc. Now, however, Null values are passed as-is to MySQL. For columns with NOT NULL attributes, this can create problems where previously none existed.

So what to do?

Though we were unable to find any documentation, investigation into the WordPress source code revealed that MySQL errors from the current page request are collected in an obscure global variable during runtime, $EZSQL_ERROR.

We can access this variable in a custom PHP function that we then trigger through one of WordPress’ action hooks. Since we want to capture all errors for a given page request, the shutdown action is the best candidate as it triggers just before PHP terminates.

The following example code block does just that. At the end of every WordPress page execution, the function looks to see if any MySQL errors were encountered. If there were any, it combines some basic runtime information (date, page, etc.) with the error details and emails it to the site administrator.

//-------------------------------------------------
// Database logging - query errors
//
// email database query errors to the contact
// specified
//
// @param n/a
// @return n/a

function db_debug_log(){

	//WP already stores query errors in this obscure
	//global variable, so we can see what we've ended
	//up with just before shutdown
	global $EZSQL_ERROR;

	try {
		//proceed if there were MySQL errors during runtime
		if(is_array($EZSQL_ERROR) && count($EZSQL_ERROR)) {
			//build a log entry
			$xout = array();

			//let's start with some environmental information
			$xout[] = "DATE: " . current_time('r');
			$xout[] = "SITE: " . site_url();
			$xout[] = "IP: " . $_SERVER['REMOTE_ADDR'];
			$xout[] = "UA: " . $_SERVER['HTTP_USER_AGENT'];
			$xout[] = "SCRIPT: " . $_SERVER['SCRIPT_NAME'];
			$xout[] = "REQUEST: " . $_SERVER['REQUEST_URI'];
			$xout[] = "\n\n\n\n";

			//and lastly, add the error messages with some line separations for readability
			foreach($EZSQL_ERROR AS $e) {
				$xout[] = str_repeat('-', 50) . "\n" . implode("\n", $e) . "\n" . str_repeat('-', 50);
				$xout[] = "\n\n\n\n";
			}

			//email it!
			//if a plugin overrides the content-type header for outbound emails, change the message body
			//below to nl2br(esc_html(implode("\n", $xout)))
			wp_mail(get_bloginfo('admin_email'), '[' . get_bloginfo('name') . '] DB Error', implode(“\n”, $xout));
		}
	} catch(Exception $e){ }

	return;
}
add_action('shutdown', 'db_debug_log');

If email isn’t desirable, whether for reasons of security or practicality, the general idea could be altered to push data via error_log() or write the contents to any arbitrary log file (preferably in a non-web-accessible location).

These techniques can help make hunting down elusive MySQL errors easier. With a proper record in place, developers can see what went wrong and where, and find a solution more quickly.

Posted By
Josh Stoik

Recommended WordPress Plugins

We’ve worked on hundreds of WordPress sites, and with that we’ve had experience with a great number of WP plugins, as well as written our own.

Over the years we’ve come to trust certain plugins and we end up using them on almost every installation.  This is a list of our go-to plugins that we can wholeheartedly recommend to others:

Security

Apocalypse Meow
Written by our own security expert, Josh Stoik, this plugin is a powerhouse. It has brute-force login protection, minimum password requirements, a history of log-in attempts, email notifications for logins from new locations, and a slew of other security-minded features. It’s the first plugin we install when we set up WordPress.

Look-See Security Scanner
Another plugin by the inestimable Josh Stoik. This plugin acts as a scanner over your WordPress installation to try and detect any malicious or unexpected code. It also analyzes your site and alerts you to measures you can take to batten down your WP installation even further.

Sock’Em SPAMbots
Yet another from Josh Stoik, this plugin gives you a variety of options for blocking SPAM comments, such as honeypots, speed tests, maximum number of links in a comment, and more. SPAMbots plays well with Akismet for even more SPAM fighting power.

Optimization

W3 Total Cache
This plugin is a must-have for a blazing fast WP site. It has both object, page, and data cache, as well as options for minification and CDNs.

Media

Post Thumbnail Editor
Sometimes the automatically cropped images that WordPress generates are just not quite right. This plugin let’s you manually recrop any image for any particular image size. A godsend for anyone with a particular sense of art direction.

Force Regenerate Thumbnails
If you’re working on an existing installation and add new image sizes, WordPress doesn’t automatically go back through old images to crop them accordingly. This plugin forces all image sizes to be regenerated, so you can be sure all your images, old and new, are properly cropped.

It also deletes image sizes that no longer exist, clearing up some space on your server. One thing to note is that it will blow away any manual crops made with Post Thumbnail Editor. For that reason, we don’t recommend running Force Regenerate Thumbnails on a production environment, only during the development phase when specific art direction crops aren’t likely to have been set up yet.

Content Management

Advanced Custom Fields Pro
THE WordPress plugin that makes leveraging WordPress as a robust and flexible CMS easy as pie. Add custom fields to posts, pages, taxonomy, attachments, almost anything you can imagine. Add that to the variety of field types, as well as all conditional rules you can establish and you have an indispensable plugin. More than anything else, ACF Pro is our desert island plugin.

Simple Page Re-Ordering
If you’re using menu_order to order any of your post types, this plugin allows you to re-order those posts by simply dragging and dropping the posts in the desired order. Super simple and incredibly useful.

Admin Area

Admin Menu Editor
Admin Menu Editor gives you tools to customize the admin dashboard menu. You can add custom links, or hide existing ones. We find it useful for hiding development-related menu items from clients and cleaning up the menus of unecessary clutter.

Admin Columns
This plugin lets you customize columns to post listings in the backend. You can hide existing columns or add new ones, with options like featured image, word count, custom fields, and more. It also has an ACF Pro add on so you can easily map ACF fields to the columns.

Admin Collapse Subpages
If you have a lot of subpages, this plugin is a must. As the name might imply, it provides the ability to collapse subpages so only top-level pages are immediately visible. It makes it much easier to navigate a subpage-heavy backend.

Misc

Search Everything
Improves the WordPress search by allowing you to customize exactly where a search looks for matches. You can add search support for custom fields, custom taxonomies, attachments, and more.

While we use other plugins as necessary, we try to keep plugin use to a minimum on any given project to avoid conflicts and instability. The plugins listed here always make the cut because of how useful and reliable they are.

Posted By
Tiffany Stoik

WordPress Multi-Parameter Search

For our work on the Lichter Realty website, we were tasked with building a multi-parameter property search.

Lichter wanted their clients to be able to filter properties based on multiple criteria: contract type, property type, square footage, and availability.

Screen Shot 2015-09-28 at 6.58.55 AM

 

Since the Lichter site is built in WordPress, to achieve this we had to build out a way to dynamically modify WP Query based on the user’s selections. To make this easier, all of the properties have multiple taxonomies to handle these various parameters, and a set of custom fields to manage availability.

First, let’s build out a form so users can make their selections. We’re using GET as our method so a filtered search ends up with shareable URLs. GET is the default, but I like to set it anyway to make it easier to figure out what’s going on at a glance.

Most of the parameters are using checkbox inputs so we can select multiple values. The exceptions are contract type and availability, which have all options, so we can use radio buttons.

The checkbox options get input names with [] at the end to make sure our values get saved in an array. The values for each input is the ID of the associated taxonomy term, except in the case of the all options.

Note: In the live site, there is more markup for presentational purposes, but for simplicity I’ve stripped that out here so we can focus on the inputs.

<form method="get" class="property-filters">
	
	<!-- CONTRACT TYPE -->
	<fieldset class="contract-type">
		<div class="accent-sans">View properties that are:</div>

		<input type="radio" id="contract-type--sale" name="contract-type" value="30" />
		<label for="contract-type--sale">For Sale</label>
		
		<input type="radio" id="contract-type--lease" name="contract-type" value="31" />
		<label for="contract-type--lease">For Lease</label>

		<input type="radio" id="contract-type--all" name="contract-type" value="all" checked />
		<label for="contract-type--all">All</label>
	</fieldset>

	<!-- PROPERTY TYPE -->
	<fieldset>
		<div class="accent-sans">Property Type:</div>
		
		<input type="checkbox" id="property-type--industrial" name="property-type[]" value="4" />
		<label for="property-type--industrial">Industrial</label>

		<input type="checkbox" id="property-type--flex-space" name="property-type[]" value="6" />
		<label for="property-type--flex-space">Flex Space</label>

		<input type="checkbox" id="property-type--loft-office" name="property-type[]" value="5" />
		<label for="property-type--loft-office">Loft/Office</label>

		<input type="checkbox" id="property-type--commercial" name="property-type[]" value="3" />
		<label for="property-type--commercial">Commercial</label>

		<input type="checkbox" id="property-type--land" name="property-type[]" value="27" />
		<label for="property-type--land">Land</label>
	</fieldset>

	<!-- SQUARE FOOTAGE -->
	<fieldset>
		<div class="accent-sans">Square Footage:</div>

		<input type="checkbox" id="sqft--5kless" name="sqft[]" value="7" />
		<label for="sqft--5kless">5k &amp; Less</label>

		<input type="checkbox" id="sqft--5k10k" name="sqft[]" value="8" />
		<label for="sqft--5k10k">5K - 10K</label>

		<input type="checkbox" id="sqft--10k15k" name="sqft[]" value="9" />
		<label for="sqft--10k15k">10K - 15K</label>

		<input type="checkbox" id="sqft--15kgreater" name="sqft[]" value="10" />
		<label for="sqft--15kgreater">15k &amp; Greater</label>
	</fieldset>

	<!-- AVAILABILITY -->
	<fieldset>
		<div class="accent-sans">Availability:</div>

		<input type="radio" id="availability--now" name="availability" value="now" />
		<label for="availability--now">Now Available</label>

		<input type="radio" id="availability--soon" name="availability" value="soon" />
		<label for="availability--soon">Coming Soon</label>

		<input type="radio" id="availability--all" name="availability" value="all" />
		<label for="availability--all">All Units</label>
	</fieldset>

	<button type="submit" class="btn red">Filter</button>
</form>

You might have noticed above that availability works a bit differently than the other options. Availability is a date based filter. In the backend, we have custom fields (lovingly created through the help of Advanced Custom Fields Pro).

The first field is a checkbox to indicate that there is availability at this property, or soon will be. This is so completely unavailable properties can be left out of the listings entirely. Once that’s checked, a date field is presented, and the administrator can pick the availability date.

If the date is today or before, that property is considered available now. If the availability date is after today, it’s considered available soon. We’ll see how these work in the query later on.

Now that we have the form set up, we can work on our query.

First, let’s grab the paged variable and then reset the query so we can use it however we want. We want to make sure to capture the paged variable before the reset, otherwise it just won’t be there!

$paged = ( get_query_var('paged')  ? get_query_var('paged') : 1 );
$wp_query = null;
$wp_query = new WP_Query();

Now we can set up base arguments for our query. These arguments are used for the initial state of the properties page, as well as the base for the filtered searches.

// BASE ARGS

$args = array(
	'post_type' => 'property',
	'orderby' => 'meta_value_num',
	'order' => 'ASC',
	'meta_key' => 'availability_date',
	'meta_compare' => 'EXISTS',
	'meta_query' => array(
		array(
			'key' => 'available_now__soon',
			'value' => true,
			'compare' => 'EXISTS',
		),
	),
	'paged' => $paged
);

We’re using the first meta_key and meta_compare arguments to make sure that the availability date field actually is present. We can then set orderby to meta_value_num to order the properties by their availability date. Then we use a meta query to further ascertain that the available now or soon flag is set to true.

A property could have once had an availability date set, but then had their availability turned off. In this case, the availability date field would still evaluate as existing, so we need this double check.

Technically, we don’t need a checkbox at all to toggle availability. Instead, we could have instructed the site administrators to leave the date field blank for unavailable.

But this is a less intuitive interface for them, so we’ve included the checkbox for added usability, even if it makes our query slightly more complicated.

Now, let’s check if anything has been searched, or if we can just go along our merry way. We’re going to need to check whether each parameter has been toggled more than once in the following code, so let’s save the answers in variables before we start our checks. We want to check:

  1. if the array key exists in GET for this parameter
  2. if we’re expecting the values to be an array (all the radio inputs in our form), verify that it is an array and
  3. if it is an array, that there is at least one value present in the array

If all the appropriate criteria are met, the variable is set to true.

// ARE WE FILTERED?

$property = (array_key_exists('property-type', $_GET) && is_array($_GET['property-type']) && count($_GET['property-type']));
$sqft = (array_key_exists('sqft', $_GET) && is_array($_GET['sqft']) && count($_GET['sqft']));
$availability = (array_key_exists('availability', $_GET));
$contract = (array_key_exists('contract-type', $_GET));

While we’re setting up variables, let’s set one up to help us keep track of whether or not any of the taxonomy-based filters have been toggled. This will help us check whether or not we need to add a tax query to WP Query later on.

// set up an array to hold our active taxonomy based filters
$taxables = array();

Now that we have our variables set up, let’s open up a big if statement. We’re going to check if any of the filters have been toggled. All of our query modifications will happen inside this if statement.

You’ll notice that for availability and contract type, we not only check their existence, but if they’re set to all. all is the default, so it technically counts as untoggled.

if($property || $sqft || ($availability && $_GET['availability'] !== 'all') || ($contract && $_GET['contract-type'] !== 'all')) {

}

If any one of the above criteria are met, we move forward.

Before we get going with the heavy lifting, let’s refresh our memories about taxonomy queries. They generally look like this:

$args = array(
	'tax_query' => array(
		'relation' => 'AND',
		array(
			'taxonomy' => 'movie_genre',
			'field' => 'slug',
			'terms' => array( 'action', 'comedy' ),
		),
		array(
			'taxonomy' => 'actor',
			'field' => 'term_id',
			'terms' => array( 103, 115, 206 ),
		),
	),
);
$query = new WP_Query( $args );

We now know that a tax query is an array, with each taxonomy filter its own array within that, and that we should set the relation to AND in case we have more than one. Let’s set up a variable to hold our tax query parameters:

$tax_query = array('relation' => 'AND');

Now let’s get property and square footage going. They work exactly the same way except we’ll pass different values to them. We want to iterate through all the values passed in GET for that parameter and add them to a $terms array.

We can then compose an array inside $tax_query with the taxonomy and the values needed. We’re also adding our check value ($property or $sqft) to the $taxables array.


// IF PROPERTY TYPE FILTER IS SELECTED

if($property) {
	$taxables[] = $property;
	$terms = null;

	foreach($_GET['property-type'] as $property_type) {
		$terms[] = $property_type;
	}

	$tax_query[] = array(
		'taxonomy' => 'property_type',
		'field' => 'term_id',
		'terms' => $terms
	);
}

// IF SQUARE FOOTAGE FILTER IS SELECTED

if($sqft) {
	$taxables[] = $sqft;
	$terms = null;

	foreach($_GET['sqft'] as $sqft) {
		$terms[] = $sqft;
	}

	$tax_query[] = array(
		'taxonomy' => 'square_footage',
		'field' => 'term_id',
		'terms' => $terms
	);
}

Contract type works similarly, except we also need to check that the value isn’t all before proceeding, and we don’t need to iterate through terms since availability isn’t an array.

// IF CONTRACT TYPE FILTER IS SELECTED

if($contract && $_GET['contract-type'] !== 'all') {
	$taxables[] = $contract;

	$tax_query[] = array(
		'taxonomy' => 'contract_type',
		'field' => 'term_id',
		'terms' => $_GET['contract-type']
	);
}

Now that we’ve run through all the possible taxonomy-based filters, we can use that $taxables array. We had been adding items to it if a given taxonomy parameter had values toggled within it. Now we can use that to check if we need to add our $tax_query to the our query arguments.

// IF ANY TAXONOMY FILTERS ARE SELECTED, WE ADD THE TAX ARGS TO OUR QUERY
if(count($taxables)) {
	$args['tax_query'] = $tax_query;
}

All that’s left is availability. For availability, we’re going to be adding to the existing meta query. We want to pass today’s value and the availablity_date key. We have to make sure to set the type to date or our comparisons won’t work properly. The comparison will vary between less than or equal to for now or greater than for soon.

// IF AVAILABILITY FILTER IS SELECTED

if($availability && $_GET['availability'] !== 'all') {
	$meta_query = array(
	'key' => 'availability_date',
	'value' => date('Y-m-d', current_time('timestamp')),
	'type' => 'date'
	);

	if($_GET['availability'] === 'now') {
		$meta_query['compare'] = '<=';
	}

	else {
		$meta_query['compare'] = '>';
	}

	$args['meta_query'][] = $meta_query;
}

And that’s it for our if statement. Let’s take a look at it all together:

if($property || $sqft || ($availability && $_GET['availability'] !== 'all') || ($contract && $_GET['contract-type'] !== 'all')) {

	$tax_query = array('relation' => 'AND');


	// IF PROPERTY TYPE FILTER IS SELECTED

	if($property) {
		$taxables[] = $property;
		$terms = null;

		foreach($_GET['property-type'] as $property_type) {
			$terms[] = $property_type;
		}

		$tax_query[] = array(
			'taxonomy' => 'property_type',
			'field' => 'term_id',
			'terms' => $terms
		);
	}


	// IF SQUARE FOOTAGE FILTER IS SELECTED

	if($sqft) {
		$taxables[] = $sqft;
		$terms = null;

		foreach($_GET['sqft'] as $sqft) {
			$terms[] = $sqft;
		}

		$tax_query[] = array(
			'taxonomy' => 'square_footage',
			'field' => 'term_id',
			'terms' => $terms
		);
	}


	// IF CONTRACT TYPE FILTER IS SELECTED

	if($contract && $_GET['contract-type'] !== 'all') {
		$taxables[] = $contract;

		$tax_query[] = array(
			'taxonomy' => 'contract_type',
			'field' => 'term_id',
			'terms' => $_GET['contract-type']
		);
	}


	// IF ANY TAXONOMY FILTERS ARE SELECTED, WE ADD THE TAX ARGS TO OUR QUERY

	if(count($taxables)) {
		$args['tax_query'] = $tax_query;
	}
	

	// IF AVAILABILITY FILTER IS SELECTED
	
	if($availability && $_GET['availability'] !== 'all') {
		$meta_query = array(
			'key' => 'availability_date',
			'value' => date('Y-m-d', current_time('timestamp')),
			'type' => 'DATE'
		);

		if($_GET['availability'] === 'now') {
			$meta_query['compare'] = '<=';
		}

		else {
			$meta_query['compare'] = '>';
		}

		$args['meta_query'][] = $meta_query;
	}
}

After that, all we need to do is add call a new query based on our arguments:

$wp_query->query($args);

And that’s it! It even works with that mysterious devil, pagination.

Be sure to check out the live search on Lichter Realty.

Posted By
Tiffany Stoik

WordPress Object Cache

It is not unusual for WordPress to run dozens or even hundreds (yikes!) of database queries when putting together a page. What’s worse, these queries aren’t the sort from children’s bedtime stories. They’re the dirty ones, full of temporary tables, JOINs on JOINs on JOINs, generic data types, and insufficient indexing. They’re the MySQL equivalent of The Wire.

As traffic loads increase, these computationally-heavy operations can quickly lead to a bottleneck, making your site sluggish or bringing it offline altogether.

To get a better idea of your own database use (or abuse), install a plugin like Query Monitor, which puts detailed query stats in the admin toolbar.

If you’re nearing the limit of what MySQL can handle, there are a few basic things you should consider doing:

  1. Go through your plugins and deactivate and delete anything that isn’t being used.
  2. Set reasonable post limits (10 or fewer) for archive pages.
  3. If you have a custom theme, try to minimize the number of secondary queries being run inside The Loop.

Beyond that, well, that’s the purpose of this article: Object Caching!

WordPress has the ability to cache query results (and other key/value data) in memory for later retrieval so it doesn’t have to pester MySQL on repeat requests.

This can dramatically reduce the load on MySQL, while maintaining comparable speed.

The main disadvantage of Object Cache is that objects are, well, cached. This means that changes made in the backend might not be immediately reflected on the front end.

This can be a deal breaker for applications with transactional data like e-commerce sites, unless the code contains strategic calls to wp_cache_flush(). But for content-driven sites like blogs and portfolios, it can be the perfect solution.

Object Cache also takes over handling of “transient” data, which otherwise get stored in the wp_options table. This will both speed up plugins and themes that rely on the transient API, and also reduce bloat in the database (there is no automatic garbage collection process run against wp_options, so data remains forever, and ever, and ever… (unless the same cache key is requested again)).

WordPress Object Caching is designed with extensibility in mind. All it needs is an API for key/value storage and retrieval.

There are innumerable candidates for the job, so let’s just focus on some of the most common:

XCache

XCache is my favorite PHP opcode cacher (opcode cache, incidentally, will also speed up the execution of your PHP scripts in general).

It is lightweight, scalable, and supports the latest versions of PHP.

To get started, install the XCache PHP extension (available in most Linux repositories), tweak the INI settings* (variable cache is the relevant feature here), and restart PHP.

After that, you can then enable Object Caching in WordPress by installing XCache Object Cache Backend or a more comprehensive caching solution like W3 Total Cache.

If you have multiple sites running on the same server, you need to ensure you are running version 3.0.3 or later.

The XCache extension comes bundled with admin scripts you can copy to your web root to get an idea of how cache is being utilized. You should install this after it has been running for a while to see if the memory allocations need to be raised or lowered (just make sure you restrict access, and delete it when you’re done!). Remember, the memory settings are per-process, so don’t get carried away.

APC

APC is another PHP opcode cacher, but it is no longer actively developed.

Unless you are running an older version of PHP or your hosting environment comes bundled with it, XCache is a better option.

To get started, install the APC PHP extension, tweak the INI settings, and restart PHP. You can install a standalone plugin like APC Object Cache Backend or, again, go with something like W3TC.

There remains, however, one excellent use case for APC: Facebook’s HHVM engine supports it out of the box! If you have already replaced PHP with HHVM, just install the APC Object Cache Backend plugin and you’re good to go.

Redis

Redis is a powerful key/value caching solution with support for multiple servers.

For complex web applications consisting of multiple servers, it is an ideal solution as the cache can be shared across more than one machine.

For more simple setups, it is a bit much, and noticeably slower than XCache or APC.

To get started, install the Redis server and PHP extension (if you are running HHVM instead of PHP, the “extension” is built-in). Once you have that configured, you can install the Redis Object Cache plugin.

Posted By
Josh Stoik

BBG Tips: Keep WordPress Tidy

WordPress is kind of magical. It gives site operators the power to quickly and effortlessly extend functionality, tweak design, and preview and post new content.

However, this power of immediate evolution – a key feature that has made so many insightful blogs about cats sleeping in weird places possible – can, over time, lead to clutter, increased hardware costs, and even security vulnerabilities.

Organized Desk

Keeping WordPress tidy is as important as keeping your workspace clean.

Thankfully, a little bit of spring cleaning will go a long way. (Even if you don’t get around to it until the end of summer.) There are two areas to focus on:

Disk

First and foremost, conduct a quick census of the plugins installed on your site. If you notice any that aren’t actually being used, deactivate and delete them. All plugins contribute to the overall resource demands made of your server, so at best, unused plugins are needlessly slowing things down.

More importantly, plugins also add a lot of code to your site, code which may contain bugs or security weaknesses that a hacker would love to leverage against you.

Themes are another area that can grow quite cluttered over time. Even though inactive themes won’t contribute one way or another to your site’s performance, you should still delete them from the server as they might contain exploitable security vulnerabilities.

Byte for byte, orphaned thumbnails from uploaded images comprise the most wasted disk space on the average aging blog.

Every time an image is uploaded to WordPress, anywhere from a handful to a boatload of differently-sized thumbnails are generated and saved to the server. The precise dimensions of the thumbnails vary from theme to theme, so for sites that have switched designs, this can lead to a lot of images cropped at resolutions that will never be accessed again.

The plugin Force Regenerate Thumbnails will take care of this, deleting all existing thumbnails, and regenerating only those that are actually required by the current theme. Depending on how many images you have, this can take a while, so go make a sandwich if you’re hungry.

Data

Your database, too, can easily start to look like the dark recesses of an attic, full of tangled and broken holiday decorations, old clothes, and haunted chests. The largest culprit here is usually post revisions.

WordPress maintains a history of all changes made to all posts.

This is nice because it allows you to review any changes you’ve ever made and rollback to a prior version at any time.  But this also generates a lot of bloat, particularly if you can’t decide between desert or dessert or desert or dessert.

Thankfully, this is something you can fix automatically by capping the number of revisions to some sane value. You can do this by adding the following to your wp-config.php file:

//specify the max # of revisions, 3 in this example
define('WP_POST_REVISIONS', 3);

The WP_POST_REVISIONS setting is not enforced retroactively. To remove or prune excessive revisions for existing posts, you can use a plugin like Thin Out Revisions.

The trash can also be an area of database bloat. When you delete a post, it is moved to the trash. Just like the trash on your laptop or the trash in your kitchen, items will linger forever and ever until someone bothers to empty it.

You can automate this task in WordPress, at least, by adding the following to wp-config.php:

//specify the # of days before emptying, 5 in this example
define('EMPTY_TRASH_DAYS', 5);

One last area of data bloat is one that can be really bad on some sites, and nonexistent on others: transient data.  WordPress includes an API for temporarily storing arbitrary key/value pairs for later retrieval.

Most often, transient data is used to cache results that would otherwise take a while to generate, such as a response from another server (for example, a Twitter feed) or the end result of a really convoluted query (like: find all posts published on a Wednesday about apples or oranges but not mangoes…).

By default, WordPress stores these data in the wp_options table.  Though each piece of information is given an expiration, WordPress does not do any automatic garbage collection.

Transient data is only removed if and when it is requested (after expiry).

If a given transient key is not reused, the data will outlive us all.  Fortunately, you can keep expired transient data in check with the help of the aptly named plugin Delete Expired Transients.

That’s it!  Happy cleaning!

Posted By
Josh Stoik