All posts by Sean

How and why to write Object Oriented WordPress plugins

Today I want to discuss an object oriented approach to plugin design that works no matter how small or large your plugin is going to become. Once I started doing this, I found it very difficult to return to the old way.

WordPress is… ahem… a “mature” codebase. It’s strength is not necessarily in its modern, lightweight design, but instead in its broad user base and ease of use. These two things are somewhat at odds, given how quickly programming languages evolve.

WordPress is fully compatible with PHP 5.2.9, which means that someone who set up a website 7 years ago at a cut-rate web host, will still get security updates, and, as of now, can still update WordPress to experience the latest and greatest core offerings (although maybe not the latest and greatest plugins) with no issue.

What’s changed between PHP 5.2.9 and now?

  • Introduction of Interfaces
  • Introduction of Namespaces
  • Anonymous functions
  • Anonymous classes

These are just to name a few.

And although PHP 5.2.9 does allow basic but solid object oriented programming techniques, WordPress has a developed enough codebase that a lot of WordPress is built with functions and global variables.

I don’t think you should follow their lead.

To illustrate the difference between the old “WordPress” way, and the new Object-Oriented way (which, in fairness, WordPress implements in many of its newer classes), take a look at these two code samples which do the same thing:


// Procedural
<?php
add_action('init', 'my_long_unique_hello_world_function');
function my_long_unique_hello_world_function() {
    echo "Hello World!";
    die();
}

add_action('admin_init','my_long_unique_admin_hello_world_function');
function my_long_unique_admin_hello_world_function() {
    echo "Hello Admin!";
    die();
}

// OOP
<?php
class My_Unique_Class {
    public function load() {
        add_action('init', array($this, 'init'));
        add_action('admin_init', array($this, 'admin_init'));
    }

    public function init() {
        echo "Hello World!";
        die();
    }

    public function admin_init() {
        echo "Hello Admin!";
        die();
    }
}

global $my_unique_class;
$my_unique_class = new My_Unique_Class();
$my_unique_class->init();

At first glance, the second example is much more verbose, so it’s probably a load worse, right? Granted, for an example with only one action hook, this is overkill. But most plugins do not have just one action hook. Most plugins have several.

And when you get to several action hooks, this becomes really, really helpful.

First of all, rather than having to write a very long function name for your action, you can often write exactly what it is. For example, in my classes, I try to add one function per action per class, so that the init hook always points to the class::init() method. This can make it easier for me to track down coding issues.

Second of all, you may have noticed my little global at the bottom. Because WordPress hasn’t offered a better solution, this is still unavoidable. However, it still dramatically reduces the amount of pollution many plugins would cause in the global scope. Remember, each function outside of a class is also part of the global scope! That increases the likelihood of collisions with other plugins.

Third, this allows you to make full use of object scoping, making things private and protected for internal use only. This may not seem like a big deal, but it can do wonders to remove your dependency on global variables. I’ve used this to build a number of plugins, a good example of which is a footnotes plugin, where each [cite] shortcode is added to a class property and printed as needed (Gist here). Is it strictly necessary to use classes to make something like this work? No. Does it make it a lot easier and dramatically reduce the chance for collisions? Yes!

There’s a lot more to love about Object Oriented programming, including Interfaces, Namespaces, and much more. I’m going to be diverging from the WordPress world to cover some of these concepts, but they should still apply pretty easily. Stay tuned!

Two ways to speed up WordPress

It’s widely held that when you add too many plugins, WordPress gets slow. But what if you need these plugins? Fortunately, you can speed up WordPress on your website, regardless of plugin count.

The fact of the matter is, speed of WordPress sites is almost never a problem with PHP or MySQL, or even Apache. While these can all play their part in slowing a website down, it is generally not the performance killer. The real performance killer? Render-blocking scripts. If you want to speed up WordPress, this is possibly the most important area to tackle.

Check out your Google Page Speed to see what’s happening here. If you’re running a standard WordPress install and have tried plugins that promise faster page speeds with things like concatenation and minification, you’re probably not going to see much difference. That’s because while it will take the browser less time to read these files, and it doesn’t have to read whitespace, it still has to read a lot of the same lines. 50% of a big file, is still a big file.

Think of it this way: It takes you a few milliseconds to load an HTML page – even a PHP rendered one, if it’s well written. Now, imagine loading that same script 20 or 30 times. It will probably take you 20 or 30 times as long. This is especially true on an Apache server because frequently Apache calls these files directly (unless you’re using a caching system – more on that later). JavaScript and CSS files work similarly. Your web page needs to open up these files and process them before being served to the browser. What makes JavaScript a real killer is that the browser needs to parse and execute the JavaScript, loops and all. By default, it does this before the website loads. Additionally, in modern websites, JavaScript operations can be very intensive, so that, taken as a whole, you may have more JavaScript than you do HTML on a given page. This adds a lot of time to your page load.

#1: Asynchronous scripts to the rescue!

It doesn’t take much effort to implement a strategy that can noticeably speed up WordPress. You can do this by making your Javascript asynchronous and/or deferred, which, really simply, means that it can open after your website has loaded. In most cases, the lack of scripts on page load won’t be noticeable, because your scripts will load within a few seconds. What will be noticeable is that your website is suddenly much faster.

There are a few good asynchronous/defer script plugins out there. The two that I’ve used are:

  • Async Javascript – This is a very simple plugin that does what it says it does. It does not defer jQuery by default… Which is good, because that tends to trigger all sorts of errors. You can also exclude files simply by adding the script name, and select between defer and async. I tend to go with async unless I’m getting too many errors, because it guarantees the best page speed. Unfortunately, when a lot of dependencies are required, sometimes it is not feasible. This is also important for any plugins that interfere. In my opinion, this is the easiest plugin to get set up and working the way you want it to work.
  • Fast Velocity Minify – Another great option for plugin developers, this also caches, minifies, and concatenates your files if you so desire. The concatenation is a bit overkill here, but the fact that it has minification makes it a good option to take care of another common Google Page speed gripe.

Important: Make sure you test this out first on a local or staging server.  If you don’t have one, please be aware that this is highly likely to need some fine-tuning, so test your web pages immediately. To see what’s going wrong, in Chrome or Firefox, right click on the page and select Inspector. Then, navigate to the Console tab. You’ll need to track down the specific JavaScript errors. For example, when I received an error for our plugin, Featured Image Pro, that “imagesLoaded” and “masonry” could not be found, I had to create an exception for these two files, which exist in /wp-includes/js/. If this doesn’t make sense to you, STOP and get a developer to help you.

#2 Leverage Browser Caching

Another great way to speed up WordPress is to utilize browser caching. This is something I’m frequently guilty of skipping, but can help you speed up WordPress on your site, because your server isn’t hit when your browser notices that a file it needs is already stored locally. If you have control over your server and you have more than one website, you can do this universally or in your Virtual Host configuration.

Otherwise, put it in your .htaccess file.


<IfModule expires.c>
    ExpiresActive on
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
    ExpiresByType image/x-icon "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType application/x-javascript "access plus 1 year"
    ExpiresByType text/javascript "access plus 1 year"
    ExpiresByType audio/ogg "access plus 1 month"
    ExpiresByType image/bmp "access plus 1 month"
    ExpiresByType image/gif "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType image/svg+xml "access plus 1 month"
    ExpiresByType image/webp "access plus 1 month"
    ExpiresByType video/mp4 "access plus 1 month"
    ExpiresByType video/ogg "access plus 1 month"
    ExpiresByType video/webm "access plus 1 month"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    ExpiresByType font/eot "access plus 1 month"
    ExpiresByType font/opentype "access plus 1 month"
    ExpiresByType application/x-font-ttf "access plus 1 month"
    ExpiresByType application/font-woff "access plus 1 month"
    ExpiresByType application/x-font-woff "access plus 1 month"
    ExpiresByType font/woff "access plus 1 month"
    ExpiresByType application/font-woff2 "access plus 1 month"
</IfModule>
<IfModule !expires.c>
    <IfModule headers.c>
        <filesMatch ".(css|jpg|jpeg|png|gif|js|ico|woff)(\?.*)?$">
        # cache 30 days
        Header set Cache-Control "max-age=2592000, public"
        </filesMatch>
    </IfModule>
</IfModule>

This will cache (non third-party) javascript as it appears in WordPress. If you have control over your server, it is probably easier to have mod_expires on, so type in:

a2enmod expires
service apache2 reload

Many servers will have this enabled by default. If not, hopefully they have headers enabled by default.

You can test your cache results using this tool.

There are few more advanced features, like gzip compression, and more advanced server setups, like Varnish/Apache, or Nginx/PHP-FPM. that you may want to implement. However, while these will speed up your site, they don’t offer you nearly the same bang for your buck in terms of obvious performance increase compared to time spent.

How To Install Composer programatically

If you want to automate the download and installation of Composer, chances are you are trying to figure out how to install Composer programatically. For example, I have a setup at work where I have an install script to create local developer environments in vagrant, which includes Composer. The fatal mistake is copying the Composer download script directly from the website. The reason for this is that the signature regularly changes as the software updates, and Composer downloads with a hard coded signature will fail. Fortunately, Composer offers a very easy way to verify signatures programatically.

To use it in Linux, you can substitute the signature string with:

$(curl -Ss https://composer.github.io/installer.sig)

The full syntax:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === '$(curl -Ss https://composer.github.io/installer.sig)') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

The end result of this is that you can install composer on a new machine without having to constantly check the signature on the web.

This is useful if you need a script, or just want a simple executable that downloads and installs Composer without having to visit the web page every time.

6 Must-Know Bash Commands for Web Developers

If you’re developing on Linux, you probably are either familiar with, or getting familiar with, Bash. If you are developing on a Mac, however, you may be less familiar.

If you have never or rarely opened up your Terminal app, you are missing out on a giant world of productivity. Here I’m assembling what I think the best Bash commands for a newbie in the world of Bash to familiarize themselves with. This isn’t even close to everything. But, my goal is to give you not too much that you can’t memorize, but enough to convince you of the value.

Bash Commands

  1. ls – Let’s you see what’s in your current directory.
  2. cd – change directory.
  3. tail – You can use tail to look at logs. For example, if you want to view a WordPress log, type
    tail -f <path>/wp-content/debug.log

    The outcome? You’ll have a stream of new log data show up in real-time.

  4. grep – This is an indispensable command to help you find things within files. Type
    grep '<search>' <search_file_path>

    You can also use an asterisk to search every file within a folder. Here are some applications:

    1. grep -nr '<search>' <folder>/*:

      searches (-r) recursively and includes a (-n) line number.

    2. grep -l '<search>' *

      Finds any (-l) file in the current directory that contains your search word. Returns the file name one time. Sometimes it’s a little easier to just see the files, rather than see line information or how many times the search shows up.

  5. find – I use this all the time instead of the Finder search. The easiest way to use this is to change directories (cd) until you get to a folder you want to search within. Then, type:
    find -name "<search_file>"

    Asterisks work here as wildcards. So, if you want to find all JavaScript files that are in any child folder is

    find . -name "*.js"

    Note that you frequently do not need the quotation marks. I include them because some versions/searches require it. The period after find specifies the file path, and is not required in Linux but is required on Mac terminals. To search a specific path that you are not currently on, you can replace the dot with a path.

  6. man – This is the last command I’m going to leave you with, and it’s also the most important. I am barely scratching the surface with many of these commands. man allows you to learn what a command is capable of on your own. This includes several options and expected syntax. While Google can be very useful, man should probably be your first stop to learn what a command is capable of. Try typing the following to see what other options you can pass along in a search:
    man grep

     

  • Pro Tip<tab> – This isn’t a command, but it’s a really useful key. It will autocomplete a directory path or command for you. If there’s ambiguity, double tapping tab will list options for you.

Feeling overwhelmed? That’s all right. You don’t need to capture all of these commands at once. Ultimately, mastering one or two commands at a time will drastically improve your productivity as a web developer. The best part is, these tools will also make it much easier for you to use programs like VVV, which jumpstarts your WordPress development by installing a virtual Ubuntu linux machine on your Mac.

Keep tuned in, while I offer more tips. Do you have a favorite command that helped you when you were just starting out? Feel free to share!

Can’t Log In using HyperDB? Here’s how to fix it

I recently had an issue where a high availability server I was running with HyberDB and a master/slave relationship wasn’t letting me log in. I spent a lot of time digging around, and couldn’t see any issues. SHOW SLAVE STATUS on my MySQL replication server showed no errors either.

It turns out, the big issue was latency. WordPress seeks to verify your session after you’ve logged in. If you are verifying on a different server than the one from which you’re inserting, there is a chance that you may not actually get the data on time.

The solution? Add this to your db-config.php file:

/**
 * Add a sleep setting, to ensure that setting
 * cookies and all verification happens after
 * replication has already taken place.
 * If you replication is taking more than
 * 1 second, you may have a server latency issue.
 */
add_action('set_logged_in_cookie', function() {
    sleep(1);
}, 10, 0);

That should fix your issues.

Is WordPress/PHP Inherently Insecure?

I wanted to take the time to address something I hear all the time: WordPress is inherently insecure. Rather than bury the lead, I’m going to come right out and say that, no, WordPress is no more insecure than any other large-scale CMS in usage right now. There is a second question: Is PHP inherently more insecure than other web programming languages? Again, the answer is no. While PHP at one point spent no time considering security, many of the critiques of PHP security are no longer accurate.

Another, more honest answer to this question is: Yes, WordPress and PHP are both vulnerable to hacking. As is everything online. Make no assumptions about security. It is always possible to write bad code that leaves open a vulnerability. Instead of assuming security, understand how you can limit your exposure. And with WordPress and PHP, this is very possible.

So, let’s review, and deconstruct some common complaints about WordPress and PHP security:

#1 WordPress sites cannot be secured

I installed WordPress in a very large environment. The very first thing I did after switching the website to WordPress was review the logs. It may surprise some people that almost immediately I noticed automated attacks against the website. Of these attempts, any guesses to the percentage that were done against WordPress core? Bonus points, if you guess how many were done against plugins and themes that I had installed on my website.

The answer? 0. These vulnerabilities are all well documented and against themes and plugins that are no longer on the WordPress theme and plugin marketplace, or have been updated to address the underlying issue. The folks who contribute to WordPress put a lot of effort into making it easy to report vulnerabilities. In fact, when a vulnerability is discovered in WordPress Core, most websites receive a security update automatically. WordPress is so good at this that they backport updates to versions as old as 3.7 (as of writing this, 4.7 is being developed, and 3.7 is 3 years old. This is a more generous security support policy than PHP).

That’s not to say you’re secure! There are a lot more ways to make a WordPress site insecure than to keep it secure. Because most vulnerabilities are against plugins and themes, make sure you keep your plugins and themes updated. For many, it might be easier to enable automatic updates for plugins. The downside is that if a plugin introduces a new bug, it could cause an issue with your website. WordFence is a security plugin that warns you when your plugins are out of date, and is my favored approach. That way, you can test your plugin updates first.

#2 But if WordPress can be secure, why are WordPress sites hacked so often?

That’s simple: Because a plurality of websites online run on WordPress. I’m not going to get into numbers, because there are a lot out there. Suffice it to say that it’s the most popular CMS out there. Because it’s so easy that a user can set it up, there are many WordPress installs that are poorly set up. There are also a lot of cut-rate web hosts that offer WordPress because it’s free and popular, but they make no steps to update vulnerabilities. That means there are a lot of very, very old WordPress installs with very, very outdated plugins. This percentage may be higher than, say Drupal, or Django, but I am not convinced. Rather, the sheer number of outdated installs are higher.

The argument that other CMS’s are more secure reminds me of the old concept that Apple computers can’t be hacked. This was disproven as soon as Mac became widely used enough for it to be economically beneficial to discover exploits and take advantage of them. Meanwhile, Windows has recently had far fewer vulnerabilities than Mac or Linux. That is partially because of a long-fought struggle to become more secure after some very insecure releases, but partially because most websites run on Linux, and a lot more users are on Mac these days, including yours truly. In any case, I digress. The point is that WordPress exploits are created so often because it’s the biggest target. It also means that there’s a lot of white hat security reviewers out there who are constantly trying to stay ahead of the black hats.

#3 PHP is Inherently Insecure

I want to start by saying I’m not claiming PHP is the best web language. I am only addressing the core question of whether PHP is fundamentally more insecure than other languages.

This next two paragraphs are going to get technical. If you don’t understand it, that’s OK. Just let your eyes glaze over or skip them.

There was a time that PHP was primarily a webforms language run off of CGI. Its claim to fame was that it ran with very little special configuration, and could do web scripting very easily. It was a security nightmare. What’s worse, it was so easy to program that idiot hackers, like myself at the time, could write the worst code imaginable. What’s worst, is that it was difficult to write good code, because there was no object oriented programming. When PHP finally offered object oriented programming and eliminated some of the worst global variable threats (that made it possible to view and manipulate server variables), it still wasn’t great. The syntax was often ugly, scoping was brutal, etc. Want a MySQL query to run? Well, you’re asking for a great deal of trouble. SQL injection attacks were a constant concern, because there were no prepared statements.

PHP5 addressed many of these and other issues (while still leaving some unworked right now). And what PHP5 started, PHP7 is continuing.

How can you be hacked with PHP? Quite easily. Poorly written code and old code can still leave huge vulnerabilities. Just because you can write good code doesn’t mean you have to. Still, it is becoming harder to write bad code. Which is a good thing.

So… What can I do?

Ultimately, what you can do depends on your specific situation. Security should never be an afterthought, so read on and implement what you can. This could save you from an embarrassing, expensive, or business-destroying hack.

If you are on a hosted server:

  • Make sure you’re not going cut-rate. These days, you can find good hosting that keep their infrastructure updated and provide backups, GoDaddy ($8/mo with SSD storage) and InterServer ($8/mo with unlimited bandwidth/visitors).
  • For a little more money, WPEngine ($29/mo) offers excellent service, daily backups, and more. You still need to update your own plugins, and if you want more regular backups, you can use a plugin like Updraft Plus.

If you are self-hosting:

  • Make sure you get on a regular update schedule. Linux has received some bad publicity recently for very serious vulnerabilities, such as Dirty COW and POODLE. If you are running an old version of linux that doesn’t receive updates, or if you aren’t regularly applying updates, then you are asking to be hacked, and no matter how secure your PHP code and WordPress install are, you are very vulnerable.
  • Do not set your permissions to 777, or grwxrwxrwx. This means anyone who gains access to your server – absolutely anyone – can go in and delete your website, or get your MySQL username and password, or replace all of your uploaded images with porn and your uploaded files with viruses. Yes, you should be scared.
    • Set your permissions to 771 at most for web folders, and 664 at most for web files. That allows a web site to run, without allowing a user to do whatever they want. Ideally, your wp-config.php file (or wherever you store your passwords) should not have read permissions. If your file is owned by the Apache webserver (ex. www-data) then that should not break anything. But, test this before making the change live on your server.
  • Ensure you have a program like “fail2ban” installed, and configure it to monitor both web and SSH settings.
  • Use an SSH key, and disable password access.
  • If you have a static IP address, block port 22 everywhere except from that IP address.
  • There’s a lot more you can do – this is just the bare minimum. If you’re not sure what any of this means, do not self-host. If you get most of it, keep studying, and never assume you’ve figured it all out.

For Everyone

  • I will reiterate that plugin and theme updates are very important.
  • Do not keep plugins installed and deactivated. People will still be able to access these plugin files, so if there’s a vulnerability then they will be able to exploit it as long as it is on your system.
  • Install WordFence and follow reminders to update your plugins or WordPress core. Do this regularly to avoid old code becoming a vulnerability. Additionally, WordFence comes with a great firewall that blocks suspicious IP address logins.
  • If you don’t have regular backups on your server or through your host, install Updraft Plus or another backup plugin. I like Updraft Plus because it’s easy to set up and backs up straight to your Dropbox.
  • Do not install plugins that are not widely used without understanding what they do.
  • Do not install plugins that are not on the WordPress marketplace unless you are confident in the company’s commitment to updating their code for security.
  • Do not install plugins that are not under active development. If something goes wrong, you are going to be on your own in figuring out a replacement.
  • DO prefer plugins that have a wide user base. These plugins have a higher likelihood of remaining supported.

I hope I’ve made a convincing case that it is very possible to write good code in PHP, and to keep your WordPress installation protected, while making clear the large caveat that there is a LOT of bad code out there, and that, no matter how secure you aim to be, you are not 100% safe from being hacked. Even if you try to do everything right, we are fallible, and so the best code with any level of complexity will inevitably have a bug in it.

If you always assume there’s an exploit in your website, but keep yourself updated and select your plugins and theme carefully, you are likely no less vulnerable on WordPress than on any other CMS.

Do you have any security plugins/packages you like? Let me know! I’m learning how to keep my server more secure, just like everyone else.

Getting the MySQL command on MacOS (v 10.11 and up)

If you are familiar with using the terminal on Linux, the absence of the mysql command can at times feel painful for a Mac user. While launching MySQLWorkbench is easy enough, sometimes those of us familiar with *nix shells just want to use the terminal. I spent an hour or so searching for a solution, with only MySQL server or outdated homebrew formulae to be found. Then, I realized something that should have been obvious all along.

If you have MySQLWorkbench installed on your computer, it must have some way to communicate with a MySQL server, and my money was on&mdash;wait for it&mdash;the mysql command.

Here’s how I got it back (Note: This method requires MySQLWorkBench)

First, I did a search for the path.

sudo find / -name mysql -print -quit

Then, I copied that path (in my case it was /Applications/MySQLWorkbench.app/Contents/MacOS/mysql).

Finally, I put that path into my .bashrc file.

printf "alias mysql='Applications/MySQLWorkbench.app/Contents/MacOS/mysql'" >> ~/.bashrc

I repeated the same for mysqldump.

Altogether Now

If you’re looking for an easy few lines to copy it, here goes:

printf "\nalias mysql='$(sudo find / -name mysql -print -quit)'\nalias mysqldump='$(sudo find / -name mysqldump -print -quit)'" >> ~/.bashrc

If you’re running VVV, you can easily test your connection like so:

mysql -h vvv.dev -u external -p

 # (password is external)

If you are not running VVV, that’s fine – just substitute the hostname, username, and password as needed.