All things related to web

Showing Hidden \"Uploading Files\" Settings in WordPress

Illustration

If you install WordPress these days, you won’t even know that upload path is customizable. Setting that used to be under Settings/Media is simply no longer there.

However, if you configured that setting before WordPress 3.5, you will see two additional boxes. Newer versions of WordPress simply hide them if they are left blank. And that leaves us with chicken/egg problem: you cannot change it until you already changed it once before.

Fortunately, web interface is not the only way to change settings in WordPress. We can go directly to MySQL and change settings there.

Of course, adjust database name and path according to your needs. My path is a bit weird as I keep WordPress files in subdirectory, but SQL commands look something like this:

mysql -e "UPDATE ^^wordpress^^.wp_options SET option_value='^^../content/media^^' WHERE option_name='upload_path';"
mysql -e "UPDATE ^^wordpress^^.wp_options SET option_value='^^/content/media^^' WHERE option_name='upload_url_path';"

Now you can refresh admin interface and everything will be in place.

File Hash Next to Every Download

Those downloading files over unreliable Internet connection are familiar with the curse of partially or badly downloaded file. For detecting such transmission errors, hash or CRC codes come in really handy. While none will fix your file, they will allow you to check whether bytes you received are the same bytes the server was sending.

I wanted to have SHA-256 hash codes available on my site too but I hated the idea of manually calculating them every time I upload something new. I wanted to have something that would work without any change to my usual workflow.

Solution ended up being a two separate parts. First part was generating SHA-256 hash. For this I simply created bash script to go over the every file in download and download/runtime directories:

for file in ~/www/{download,download/runtime}/*; do
    ...
    #calculate SHA
    fileBase=$file
    fileHash="$fileBase.sha256"
    fileBaseSum=`sha256sum $fileBase | cut --delimiter=' ' -f 1`
    if [ -e "$fileHash" ]; then
        fileHashSum=`cat $fileHash`
        if [ "$fileBaseSum" == "$fileHashSum" ]; then
            echo "  $fileBase"
        else
            echo "X $fileBase"
            echo "$fileBaseSum" > "$fileHash"
        fi
    else
        echo "+ $fileBase"
        echo "$fileBaseSum" > "$fileHash"
    fi
    ...
done

This script I added as a cron job to simply run every day. A new file with .sha256 extension gets magically created after execution is done.

Second part was creating a WordPress plugin. For this I wanted to keep it simple and just make it work as a short-code. Its full duty would be, whenever it finds downhash short code to create a link and, if .sha256 file exists, to set SHA-256 as its title. In practice this means SHA-256 hash would appear as a tooltip when mouse gets over the link. Visible for those who want it, but unobtrusive for normal people. :)

And yes, the code does include a bit of hard-coded styling. In my defense, I don’t plan to publish this as an official plugin and it does simplify the code quite a bit:

add_shortcode('downhash', 'snippet_downhash_shortcode_callback');

function snippet_downhash_shortcode_callback($atts, $content = null) {
    ...

    $file = $_SERVER['DOCUMENT_ROOT'] . $content . '.sha256';
    if (file_exists($file)) {
        $hash = chunk_split(file_get_contents($file), 8, ' ');
    }

    $html = '<div style="clear:both; font-size:120%; text-align:center;">';
    $html .= '&bull; <a href="' . $content . '"';
    if (isset($hash)) { $html .= ' title="SHA-256: ' . $hash . '"'; }
    $html .= '>' . $title . '</a> &bull;</div>';

    return $html;
}

To use this in code, just use downhash shortcode. For example, for my](’ . $content . ') Bimil I used:

\[downhash\]/download/bimil170.exe\[/downhash\]

This will result in the following line: [downhash]/download/bimil170.exe[/downhash]

As always, you can download and check code yourself.

PS: And yes, SHA-1 would also be ok for this particular purpose despite it being broken.

Batch Optimizing Images

I already wrote about optimizing images for your website. What I didn’t tell at that time is that, since I ran tools under Windows, this meant a lot of download/upload shenanigans. Yes, it was scriptable but annoying nonetheless. What I needed was a way to run both OptiPNG and jpegoptim automatically on the web host itself.

These pages are hosted by DreamHost which currently runs on Debian (Wheezy) and its linux environment is rather rich. Despite, neither of my preferred tools was installed and, since this was not my machine, just installing a package was also not really possible.

However, one thing I could do is to actually build them from sources. With jpegoptim this is easy as it uses GitHub for source. With OptiPNG it gets a bit more involved but nothing too far from just a basic download and compile:

mkdir -p ~/bin

cd ~/bin
git clone https://github.com/tjko/jpegoptim
cd jpegoptim/
./configure
make clean
make

cd ~/bin
wget http://prdownloads.sourceforge.net/optipng/optipng-0.7.6.tar.gz -O /tmp/optipng.tgz
mkdir optipng
cd optipng
tar -xzvf /tmp/optipng.tgz --strip-components 1
rm /tmp/optipng.tgz
./configure
make clean
make

With both tools compiles, we can finally go over all the images and get them into shape:

find ~/www -iname '*.jpg' -print0 | xargs -0 ~/bin/jpegoptim/jpegoptim --preserve --strip-all --totals
find ~/www -iname '*.png' -print0 | xargs -0 ~/bin/optipng/src/optipng/optipng -o7 -preserve

For hands off approach, I also scheduled them to run every week.

[2017-12-27: If you get error Cannot find libjpeg or you have too old version, install libjpeg-turbo-devel package.]

Missed WordPress Schedule

WordPress - missed schedule

It seems with every new WordPress version there is the same issue. For one reason or another, post scheduling stops working. Exact cause is varied but most commonly it is the caching plugin playing games.

Usual solutions for this are either manually calling wp-cron.php via wget or getting WP Scheduled Plugin. I believe most sites, including mine, need another plugin as much as pig needs a wig. I am not judging if you are into either of it, but I recommend limiting both activities.

Using curl or wget to manually execute wp-cron.php might also not work on sites that are properly secured and have most of php disabled in .htaccess to start with. Yes, you can always make an exception, but there is a better way.

First step is common, just disable standard WordPress cron behavior in wp-config.php:

define('DISABLE_WP_CRON', true);

Then either use crontab -e from command line or your web provider’s task scheduling web interface (CPanel or similar) to add following command:

/usr/bin/php -q /home/user/www/wp-cron.php

This will call upon PHP to manually execute wp-cron.php bypassing Apache and .htaccess completely. Notice that you must use full paths as cron jobs are ran in limited environment.

For my needs, a daily frequency (@daily or 0 0 * * *) is actually sufficient as I schedule my posts always for midnight. Those needing more precise time might decide to go hourly (@hourly or 0 * * * *) or even more often.

Random Blog Description for WordPress

Ages ago, back when I created my first dynamic ASP web pages, they had an ever changing tagline. Some taglines were funny, some were sad, some were crazy, but I enjoyed them as homage to the, now forgotten, BBS era. As I moved from one hand-built platform to another, I kept this feature alive.

I started blogging much later on the Google’s Blogspot and it wasn’t possible to get dynamic taglines there. Later, when I moved the whole blog to WordPress and merged it with my original pages, end result was more of a blog. And thus taglines were no more. They were relegated to manually changing Skype status to entertain a friend or two. Until now.

My goal was to create the simplest and reasonably performant way of selecting a random tagline from flat text file.

One approach fitting with WordPress would be to create plugin but I opted not to. Since I really wanted to change tagline once a day, plugin would be probably a bit of overkill. Instead I opted to (ab)use fact WordPress already has tagline-like field called Blog description and all we need to do is change it to text of our choice.

Of course, before we even come to that step, we have to extract tagline from file. Fortunately Linux offers shuf utility to randomly select one line of many. All needed is to give it a plain text file. Of course, we should escape all single quotes to avoid any SQL issues. If we (hopefully correctly) assume text file with taglines is under your control, simple escaping is sufficient:

TAGLINE=`shuf -n 1 ~/taglines.txt | sed "s/'/''/g"`

With tagline in hand we can go and change blog description directly:

mysql --execute="UPDATE wp_options SET option_value='$TAGLINE' WHERE option_name='blogdescription';"

While this will change description, if you use caching plugin, it won’t be enough. You also need to clean cache. The easiest approach is to simply delete cache folder. As we do it only once per day, this won’t be too much of a hit. Different caches might use different locations, but for W3 Total Cache I use here, following is enough:

rm -R ~/www/wp-content/cache

All left to do is getting this script to be executed daily by either using web interface of your web provider or setting it up in crontab manually.

PS: Instead of using shuf, you can use sort -R ~/taglines.txt | head -1.

PPS: Full script I use is here:

#!/bin/bash

MYSQL_USER=^^WordPress MySQL user^^
MYSQL_PASSWORD=^^WordPress MySQL password^^
MYSQL_HOST=^^WordPress MySQL host^^
MYSQL_DATABASE=^^WordPress MySQL database^^

TAGLINE=`shuf -n 1 ~/taglines.txt | sed "s/'/''/g"`

mysql --host=$MYSQL_HOST --user=$MYSQL_USER --password=$MYSQL_PASSWORD --database=$MYSQL_DATABASE --execute="UPDATE wp_options SET option_value='$TAGLINE' WHERE option_name='blogdescription';"

rm -R ~/www/wp-content/cache 2> /dev/null

Not All EOLs Are Created Equal

As I was playing with the Wordpress shortcode methods, I came upon an interesting problem.

I wanted to change text in the particular line of the shortcode content and thus standard PHP explode and implode methods seemed like a best bet:

add_shortcode('something', 'something_callback');

function snippet_pre_shortcode_callback($atts, $content = null) {
    $lines = **explode('\n', $content)**;
    $lines[1] = "My line 2";
    return **implode('\n', $lines)**;
}

Nice and simple solution that didn’t work. The big content string I was sure had some lines, wouldn’t split. It took me a while to notice the error - single quote in PHP does not specify character but string with a minimal escaping. Most of the time they behave same as the double quotes which actually allow for much richer escaping.

Most annoying was that I knew this “feature” from before. However, too much work in the proper programming languages kinda made me overlook this trivial error multiple times while debugging. After taking a “frustration break” and coming back after 5 minutes, mistake was obvious.

The easy solution would be to swap one quotes for another. However, in this case a bit nicer solution exists - use the damn PHP_EOL constant:

function snippet_pre_shortcode_callback($atts, $content = null) {
    $lines = **explode(^^PHP_EOL^^, $content)**;
    $lines[1] = "My line 2";
    return **implode(^^PHP_EOL^^, $lines)**;
}

PHP, who wouldn’t love you… :/

Batch Optimizing Images

The same image can be saved in multitude of ways. Whether it is camera phone or editing application, usually goal is to save image quickly without caring for each and every byte. I mean, is it really important if image is 2.5 MB or 2.1 MB? Under most circumstances bigger file is written more quickly and slightly bigger size is perfectly acceptable compromise.

However, if you place the image on a website, this suddenly starts to matter. If your visitors are bandwidth-challenged, it makes a difference between the load time measured in seconds or tenths of seconds. However, if you start optimizing, you can spend way too much time dealing with this. If you are lazy like me and don’t want to change your flow too much, there is always an option to save unoptimized files now and optimize later.

For optimizing images I tend to stick with two utilities: OptiPNG for PNG and jpegoptim for JPEG files. Both of them do their optimizations in a completely lossless fashion. This might not bring you the best savings, especially for JPEG images, but it has one great advantage - if you run optimization over the already optimized images, there will be no harm. This means you don’t need to track what files are already optimized and which need work. Just run the tools every once in a while and you’re golden.

I created the following script to go over each image and apply optimizations:

@ECHO OFF

SET  EXE_OPTIPNG="\Tools\optipng-0.7.5\optipng.exe"
SET EXE_JPEGTRAN="\Tools\jpegoptim-1.4.3\jpegoptim.exe"

SET    DIRECTORY=.\pictures

ECHO = OPTIMIZE PNG =
FOR /F "delims=" %%F in ('DIR "%DIRECTORY%\*.png" /B /S /A-D') do (
    ECHO %%F
    DEL "%%F.tmp" 2> NUL
    %EXE_OPTIPNG% -o7 -silent -out "%%F.tmp" "%%F"
    MOVE /Y "%%F.tmp" "%%F" > NUL
    IF ERRORLEVEL 1 PAUSE && EXIT
)

ECHO.

ECHO = OPTIMIZE JPEG =
FOR /F "delims=" %%F in ('DIR "%DIRECTORY%\*.jpg" /B /S /A-D') do (
    ECHO %%F
    %EXE_JPEGTRAN% --strip-all --quiet "%%F"
    IF ERRORLEVEL 1 PAUSE && EXIT
)

And yes, this will take ages. :)

OpenGraph

Illustration

When you want to share your posts on social networks, having a help with formatting cannot hurt. For that purpose I used to be a happy user of Facebook Open Graph Meta Tags for WordPress. However, with version 1.3 something went kaboom and I started getting “failed to open stream” errors. After a few attempts of repair I decided it was a time to search for a new plugin.

I tried quite a few of them and, while they all worked with Facebook, Google+ presented a challenge. Some outright didn’t support it, some supported it only in non-free version and quite a few of them were huge SEO systems that would bring my poor installation to its knees. Thus I figured it was a time to make my own. I mean, how hard can it be?

Well It was quite easy to get a basic callback working:

add_action('wp_head', 'medo_opengraph_wp_head_action');

function medo_opengraph_wp_head_action() {
    if (is_single() || is_page()) {
        $post = get_post();

        $title = $post->post_title;
        $type = 'article';
        $url = get_permalink($post);
    } else {
        $title = get_bloginfo('name');
        $type = 'website';
        $url = home_url();
    }

    echo '<meta property="og:title" content="' . $title . '" />';
    echo '<meta property="og:type" content="' . $type . '" />';
    echo '<meta property="og:url" content="' . $url . '" />';
    echo '<meta name="twitter:title" content="' . $title . '" />'; //Twitter
    echo '<meta itemprop="name" content="' . $title . '" />'; //Google+
}

With this simple code I would get posts/pages having their proper title and everything else simply having a generic title alongside my main URL. But that was not really enough - my images were missing. Ignoring crazy array return parameters, code was pretty straightforward:

foreach(get_attached_media('image') as $media) {
    $imageAttrs = wp_get_attachment_image_src($media->ID, 'full');
    $image_url =  home_url($imageAttrs[0]);
    $image_type = $media->post_mime_type;
    $image_width = $imageAttrs[1];
    $image_height = $imageAttrs[2];
    break;
}

echo '<meta property="og:image" content="' . $image_url . '" />';
echo '<meta property="og:image:type" content="' . $image_type . '" />';
echo '<meta property="og:image:width" content="' . $image_width . '" />';
echo '<meta property="og:image:height" content="' . $image_height . '" />';
echo '<meta itemprop="image" content="' . $image_url . '" />'; //Google+

And the last one was to get excerpt for the post description. Here wp_trim_words came in really handy:

$description = $post->post_excerpt;
if (strlen($description) == 0) { $description = wp_trim_words($post->post_content); }

echo '<meta property="og:description" content="' . $description . '" />';
echo '<meta name="twitter:description" content="' . $description . '" />'; //Twitter
echo '<meta itemprop="description" content="' . $description . '" />'; //Google+

Did it went as smoothly as it could? Not really. WordPress Codex was less than helpful, rarely telling you anything more than a function syntax. Coding was more trial and error than anything else. But I cannot really complain. Even with all tryouts it took me less than two hours to get plugin working with all the functionality I needed. I would consider that a success.

And, like a masochist I am, I didn’t stop after those two hours. I got some profile options for Facebook ID in. And then I built a settings page. Made code a bit cleaner. Reordered thing or two. Before I knew it, couple of hours passed and I had something one might call a proper plugin. And it is available for download. Just unzip it in wp-content/plugins and you are golden.

Two Factor Authentication for WordPress

Illustration

Beside getting HTTPS working, probably the most important security feature you can get for free on WordPress is two factor authentication.

How does two-factor authentication work? In addition to your usual user name and password, you get to enter a 6-digit number changing every 30 seconds or so. Since that number is based on a key only you should know, you can consider it as another password. However, due to its constant change nature, anybody snooping only gets to know your login for next 30 seconds or so. After that time has passed previously captured code becomes useless. Two factor authentication essentially makes fact your password is known irrelevant.

It is not a fool-proof protection - somebody can just steal your key in addition to your password. However, since key itself is never transmitted over wire, it makes things considerably more difficult for attacker. And it will definitely make common every day non-targeted password attacks irrelevant.

Even if you run without HTTPS (which I don’t recommend) and you have to login over public wireless (scary!) this will keep anybody snooping from getting full account details he might need to login. Yes, there is possibility of somebody using your authentication cookie but, as long as you logout, you can rest assured that nobody can login after you. In a plain-text world there are many other attacks somebody might try against you but two factor authentication closes the most obvious doors.

I personally use Two Factor Auth plugin for this purpose. Although it officially doesn’t support WordPress 4.1 I found it works perfectly fine. Installation is WordPress-simple and by default you will get a pretty usable system of getting codes mailed to your users when they attempt login.

However, each user gets an opportunity to enable “third party” delivery type. That will give QR code you just scan into e.g. Google Authenticator and you mobile phone can generate codes every time you need them. System of generating these codes is completely standardized and I am sure you can find your favorite application - whether is on desktop, mobile phone, or even a watch.

It is a small change that will help security a lot.

PS: If you have Google mail and two-factor authentication is not enabled, what are you waiting?

Missing Updated With Suffusion

Illustration

One good indicator of web page health is its status in Google Webmaster Tools. Although I probably don’t go there often enough, I do try to keep-up with warning it gives me. This time it was complaining about errors in my blog’s markup.

Quick look into Google’s Structured Data Testing Tool just confirmed that my blog’s Suffusion theme was indeed missing proper information. How can I add it in?

Solution was rather easy once I found proper place. In ./wp-content/themes/suffusion/custom/post-header.php I found line that controls display of time:

<div class="date"><span class="month"><?php the_time('M'); ?></span> <span class="day"><?php the_time('d'); ?></span><span class="year"><?php the_time('Y'); ?></span></div>

Since its original output was definitely not microformats compliant, I took simple step of extending it:

<div class="date **value-title" title="<?php the_time('o-m-d'); ?>"**><span class="month"><?php the_time('M'); ?></span> <span class="day"><?php the_time('d'); ?></span><span class="year"><?php the_time('Y'); ?></span></div>

By putting value into title, I allowed Google and microformats to be happy and my theme kept its look&feel.