SSL error when upgrading a WordPress Multisite Network

When updating to WordPress 4.0, I recently saw a scary-looking error when running the database upgrade on a network with some SSL sites. It triggered when trying to update tables for a site with an SSL certificate.

Warning! Problem updating https://blog.network.com/. Your server may not be able to connect to sites running on it. Error message: SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

To be totally honest, I’m not exactly sure why this happens, but I was able to find a way to fix it by telling WordPress to ignore SSL checks when running the database upgrade. Create a file in wpcontent/mu-plugins/ and name it something like network-upgrade-ignore-ssl.php. Put the following in the file:

<?php
add_filter('https_ssl_verify', '__return_false');
add_filter('https_local_ssl_verify', '__return_false');
?>

That’s it! You should now be able to get through your upgrade smoothly.

Shopify Image Variant Swap on iOS

A while back I was building a Shopify store for a client and I had used the Variant Images app to assign photos to individual product options. This app is pretty cool, but it has a couple of drawbacks. The dealbreaker for me was that its javascript doesn’t work at all on iOS currently.

In order to get image swapping working on iOS, I ended up writing my own simple script to detect when an option is changed, look for an image to match, and swap it into place. Implementation is pretty simple.

  1. Create your product options.
  2. Upload your images and set the ALT text to match the value of the option. If you’re selling t-shirts and you have an option called Color with variants Red, Green, and Blue, you would upload an image for each and set the ALT text on the images to “Red”, “Green”, and “Blue” in order to match them up.
  3. Insert the following code into the bottom of templates/product.liquid:
{% comment %}
Custom Image Swap - Image name must match option value

http://scottnelle.com/672/shopify-image-…nt-swap-on-ios/

{% endcomment %}
<script>
    jQuery(window).load(function($){
        // create an associative array of images, using alt text as key
        var product_images = new Array();
        {% for image in product.images %}
            product_images['{{ image.alt | escape }}'] = '{{ image | product_img_url: 'original' }}';
        {% endfor %}

        // change the featured image source
        jQuery('.product-options select').change(function(){
            if ( jQuery.inArray( jQuery(this).val(), product_images ) ) {
                jQuery('.image.featured img').attr('src', product_images[jQuery(this).val()] );
            }
        });
    });
</script>

Now your images should be swapping when you select a new option. As an added bonus, this script works with Shopify’s image zoom function. And since it’s pretty straightforward jQuery, if you need it to function slightly differently it’s pretty easy to modify. If you’d like to see it in action, check out the demo store.

Remove a specific item from an array in PHP

Following from yesterday’s more-specific post about removing items from the WordPress editor, here’s an easy way to remove a specific element from a PHP array by key instead of index:

function my_remove_array_item( $array, $item ) {
	$index = array_search($item, $array);
	if ( $index !== false ) {
		unset( $array[$index] );
	}

	return $array;
}

Usage:

$items = array( 'first', 'second', 'third');
$items = my_remove_array_item( $items, 'second' ); // remove item called 'second'

This works by searching the array for the specified item, returning its key, and then unsetting that key.

Remove a specific TinyMCE item from the WordPress editor

When filtering a row of TinyMCE buttons, here’s a way to remove a specific button by name. This is useful for cases where you’re editing the default editor instead of declaring your own editor. In this example, we’ll remove the underline button from the second row:

function my_mce_buttons_2( $buttons ) {
	$index = array_search( 'underline', $buttons );
	if ( $index !== false ) { unset( $buttons[$index] ); }

	return $buttons;
}
add_filter( 'mce_buttons_2', 'my_mce_buttons_2' );

Drop that code in your functions.php file to remove a specific item from your WordPress editor buttons. For more information about the individual TinyMCE toolbars available see this codex page. To list all buttons by name for a given toolbar, temporarily add print_r( $buttons ); to your filter callback function.

Determine if a WordPress post or page has children

Here’s a simple function to determine if a post, page, or custom post has children in WordPress. It works by getting the children of the current post and returning a count. It will return 0 (false) if there are no children and some positive integer (true) if there are children.

function has_children() {
	global $post;
	return count( get_posts( array('post_parent' => $post->ID, 'post_type' => $post->post_type) ) );
}

Use it in your page or post templates:

if ( has_children() ) {
	// do something if this item has children
}

Clean up a bloated wp_term_relationships table

Sometimes the wp_term_relationships table becomes bloated with many orphaned relationships. This happens particularly often if you’re using your site not as a blog but as some other type of content site where posts are deleted periodically. I recently worked on a site that had 18,000 term relationships for posts that no longer exist, and it was slowing the site down. In my case it was the way a real estate plugin from Placester IDX manages real estate listings, but you may find similar problems caused by other custom functionality.

Fortunately, MySQL can help you find these orphaned relationships with a pretty simple query:

SELECT * FROM wp_term_relationships
    LEFT JOIN wp_posts ON wp_term_relationships.object_id = wp_posts.ID
    WHERE wp_posts.ID is NULL;

It can even automatically delete the orphaned entries for you! Make sure you back up your database before running the following query:

DELETE wp_term_relationships FROM wp_term_relationships
    LEFT JOIN wp_posts ON wp_term_relationships.object_id = wp_posts.ID
    WHERE wp_posts.ID is NULL;

The number of rows deleted should match the number of rows returned in the SELECT query above.

Prevent WordPress from guessing if users hit a 404 error

WordPress has a feature called Canonical Redirects which attempts to make sure that users always end up on the one true URL for a given request. That’s great for SEO. Built in to this feature, however, is something that mystifies a lot of developers: when a user reaches a 404, WordPress will use some fuzzy matching try to guess what they meant and redirect them.

To me, this is pretty much the polar opposite of a canonical redirect. I’d much rather have 404s result in a helpful 404 page which I can track in analytics. It can also be very confusing when you’re trying to add your own rewrite rules to WordPress.

Fortunately, you can filter the Canonical Redirect to prevent this strange 404 behavior. Add this to functions.php in your theme:

function stop_404_guessing($url) {
	if (is_404()) { return false; }
	return $url;
}
add_filter('redirect_canonical', 'stop_404_guessing');

Now WordPress will continue redirecting to the canonical URL, unless you hit a 404 in which case it will display your 404 page as expected.

Posting some WordPress tips at the day job

During the week I work at a Vermont-based web agency called Union Street Media, where I’m fortunate to spend every day working with a great team on WordPress-powered websites. I’m going to start posting some of the things you’d usually expect to see here at scottnelle.com on the company blog. It will mostly be tips that I uncover during the work day after failing to find a good solution via Google. The first of these posts covers adding content to the end of all posts of a specific type. I’ve used that technique to build a plugin which allows our project managers to create project milestone signoff forms directly on the site.

Stay tuned for more WordPress posts from me both here on scottnelle.com and over at the USM Interactive Blog.

Connecting Slim Framework and MySQL

Slim Framework is a very light PHP framework that’s great for building web applications and REST APIs. The Slim Hello World example, found right on the homepage, will get you up and running in a matter of minutes. Once you’ve done that, the next step is to create a template and use it to display data from a database. Read on to find out how.

Database

We’ll create a very simple database to get our data from. It will have a single table, “friends,” which contains three fields: id, name, and job. Here’s the SQL for that table:

CREATE TABLE `friends` (
   `id` int(10) unsigned not null auto_increment,
   `name` varchar(255),
   `job` varchar(255),
   PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4;

INSERT INTO `friends` (`id`, `name`, `job`) VALUES 
('1', 'Sam', 'Gardener'),
('2', 'Molly', 'Chef'),
('3', 'Evan', 'Web Developer');

Database connection

Slim doesn’t come with a database connection utility of its own. You can use any database connection toolkit you like. If you have a favorite, use it!. We’ll be using the MySQLi object, which is the modern way to connect to a MySQL database in native PHP. Put the following code in index.php or stash it in another file and include that file in index.php. In my case I’ve put it in a file at lib/mysql.php.

function connect_db() {
	$server = 'localhost'; // this may be an ip address instead
	$user = 'user';
	$pass = 'pass';
	$database = 'slim_db';
	$connection = new mysqli($server, $user, $pass, $database);

	return $connection;
}

Getting the data

Index.php is the main controller for your application. If you set up the Hello World example you’ve already used it to route requests, accept variables through the URL, and return data. Now we’ll use it to fetch MySQL data and render it in a template. In this case, we’ll set up a route for ‘/’ so that when you visit the root of your application you get a list of your friends from the database. Here’s the entire index.php file:

<?php
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim(); $app->get('/', function () use ($app) {
	require_once 'lib/mysql.php';
	$db = connect_db();
	$result = $db->query( 'SELECT id, name, job FROM friends;' );
	while ( $row = $result->fetch_array(MYSQLI_ASSOC) ) {
		$data[] = $row;
	}

	$app->render('friends.php', array(
			'page_title' => "Your Friends",
			'data' => $data
		)
	);
});

$app->run();

After setting up Slim this code creates a route for ‘/’ which you’ve already seen. From there, we include the mysql connection function we created earlier and connect to the database. Next we get a record set ($result) and loop through all records, storing them as $data. Finally, we pass that data (plus any other data we need) to a template using Slim’s render() method.

Template

Templates allow you to show your data off to the world. There are many template languages that you can add to Slim using custom Views, but for now we’ll use a simple PHP file as our template. By default, templates will go in a directory called templates/ in the root of your application.

You can pass data when you render a template. In this example we’ll pass a page title and the MySQL data that we converted to an associative array previously. Here’s what our template file, named friends.php, looks like:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title><?php echo $this->data['page_title']; ?></title>
</head>
<body>
<?php
foreach ($this->data['data'] as $friend) {
	echo $friend['id'].' - '.$friend['name'].' - '.$friend['job'].'</br />';
}
?>
</body>
</html>

That’s it!

Once you’ve got all of these pieces in place, you’ll have a functioning Slim application. Just visit the root of your application and you should see a list of friends from the database!

Download the full test application with commented code