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
}
Posted on by Scott Nellé in WordPress

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.

Once you’ve deleted the unnecessary items, make sure to optimize the database table.

OPTIMIZE wp_term_relationships;
Posted on by Scott Nellé in MySQL, WordPress

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.

Posted on by Scott Nellé in WordPress

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.

Posted on by Scott Nellé in General, WordPress

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

Posted on by Scott Nellé in PHP

Canonical domain redirects with Apache Virtual Hosts

There are plenty of reasons you might have multiple domains pointing to the same site. In addition, it’s usually wise to configure your site so that it’s available at both domain.com and www.domain.com. But it’s usually a good idea to make sure all of these domain variations point to one proper, canonical domain.

There are a number of ways to set up canonical redirects in Apache. The most popular is probably using .htaccess, but you can also use Virtual Hosts. I prefer that method because it lives outside the web root, so other developers on my team are less likely to tamper with it. Here’s how you do it:

<VirtualHost *:80>
 ServerName www.domain.com
 ServerAlias domain2.com
 ServerAlias www.domain2.com
 RedirectMatch permanent ^/(.*) domain.com/$1 
</VirtualHost>

<VirtualHost *:80>
 ServerAdmin webmaster@localhost
 ServerName domain.com

DocumentRoot /var/www/domain.com/public_html
# continue configuring your site here

In this example www.domain.com, www.domain2.com, and domain2.com will all redirect to domain.com, which is the primary or canonical location of your site. After the ServerName line in the first block you can put in as many ServerAlias lines as you want, and they’ll all forward to the domain that you specify in the RedirectMatch line.

Note that if you have www in the domain of a WordPress site and you follow these instructions to remove the www, you will get a redirect loop. Instead, update your WordPress config first, and then update the virtual host config.

Posted on by Scott Nellé in Hosting, Server

Crucial skills for people who work on the web

Sideproject has written up a great list of skills for people who work on the front end of websites. It includes learning a CMS (I favor WordPress, in case you hadn’t noticed,) taking a thoughtful approach to front-end frameworks and CSS preprocessors, learning the details of Responsive Design instead of just how to hide pictures and change the navigation, and more.

We’re all working in a time when the role of a front-end developer is expanding. Being pretty good at HTML and CSS doesn’t cut it anymore. Sideproject’s post is a great guide toward beginning to think about the other skills you should master in order to be a highly versatile and employable designer/developer.

Original post: sideproject.io/web-design-skills-and-experience-musts

 

Posted on by Scott Nellé in Links

Lower the WordPress SEO meta box priority

WordPress SEO by Yoast is a great plugin, but its meta box gets high priority on your post edit screen and that can be a little annoying–particularly when it shows up in the middle of your other meta boxes. Fortunately, Yoast has put a filter in place so you can adjust the priority.

To lower the priority of the WordPress SEO meta box, you can put the following code in your theme’s functions.php file:

function lower_wpseo_priority( $html ) {
    return 'low';
}
add_filter( 'wpseo_metabox_prio', 'lower_wpseo_priority' );

Pretty simple fix for a common annoyance.

Posted on by Scott Nellé in WordPress

Convert OpenWeatherMap’s Kelvin temperatures with PHP

OpenWeatherMap.org’s API returns temperatures in degrees Kelvin, which is probably the best temperature scale for scientific use but is meaningless to most people in day-to-day life. Here are a couple of functions to convert it to your temperature scale of choice:

Fahrenheit

function k_to_f($temp) {
    if ( !is_numeric($temp) ) { return false; }
    return round((($temp - 273.15) * 1.8) + 32);
}

Celsius/Centigrade

function k_to_c($temp) {
	if ( !is_numeric($temp) ) { return false; }
	return round(($temp - 273.15));
}

If you want to preserve decimal points, you can remove or modify the round() function to get the level of precision you want. Personally, I’ve never found decimal places in temperatures useful day-to-day.

Posted on by Scott Nellé in PHP

Import multiple WordPress posts with the same name

By default, the WordPress import plugin will not create multiple posts with the same name which were created on the same date. I’m not entirely certain why this is the default, non-configurable behavior but in an era where WordPress is so much more than a blogging engine there is no limit to the number of cases where it isn’t desirable. Maybe you have a post type for business locations that is arranged hierarchically and each location has a child page called “Contact Us.” Maybe a hundred other things.

In such cases, I’ve found moving a site from my production server to the live server is problematic, because the WordPress Importer plugin discards all but the first instance of a post. Fortunately, this behavior is easily changed with a small modification to the WordPress Importer.

When the plugin iterates through all of the items in the import file, it checks to see whether or not it should create a post for the current item. It only takes a minor tweak to make it always create the post.

In your plugins directory, find ./wordpress-importer/wordpress-importer.php and look for the following bit of code, currently on line 557 as of plugin version 0.6.1. In future versions the location might be different or it might be rewritten. I’ll try to keep this article up-to-date:

$post_exists = post_exists( $post['post_title'], '', $post['post_date'] );
if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) {
...
}

Simply modify that as follows, and WordPress will create all posts as defined in the import file:

$post_exists = 0;
if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) {
...
}

By setting $post_exists = 0 you are telling the importer that the post doesn’t exist, which makes it work the way you probably want it to. I hope that this behavior will change (or be configurable) in future versions of the plugin, but for now this simple mod will get you going.

Posted on by Scott Nellé in WordPress | Tagged WordPress