Blank PDF Certificates in Moodle

I had a strange issue today with a client agency building a new LMS using Totara’s implementation of Moodle that might help someone.

The LMS generally worked fine, when the user completed a course and went to download their PDF certificate, it appeared to be generated correctly and previewed correctly on a Mac, but when viewed in Acrobat it was blank. It was a high profile project and is to be shown to the end client tomorrow, so the pressure was on.

Oddly, the client had a similar site on the same server that worked fine. I scratched my head for a while and went down a few blind alleys before noticing that the PDF generator was TCPDF and the problematic site had a slightly newer version. I took a chance and swapped the /lib/tcpdf folder from the working instance to the new and everything started working correctly.

Not sure what the cause of the problem was, but the client is happy.

 

Bulk Replacing Content in WordPress – A New Trick

We’re currently working on a project to update the site of a client whose name and branding has changed. So there are lots of instances of their name to change in the posts and postmeta tables, as well as some inline styles left by the previous developer.

For the posts table, replacing strings in the MySQL table is usually fine, if a bit fiddly, but the postmeta table is not straightfoward, particularly when you have serialised data.

Our new trick is to use the excellent BackupBuddy plugin. If you look on the Database tab of BackupBuddy > Server Tools, down the bottom there’s a section called “Database Mass Text Replacement”. Enter your find and replace text and away you go. Obviously you need to be very, very careful, backup first, check as you go along etc, but for something like a domain or an email, it’s perfect.

 

More quirks in the latest version of WordPress

One of the great things about WordPress is the ease with which it can be updated. One button press does the job, which is so much easier than some of the other CMS’ that we work with. However, there are occasionally changes that can break older versions of themes and plugins, so it’s always worth taking a backup, and ideally testing on astaging version of the site.

We’re currently helping one client upgrade their estate to the latest version and have found a few issues that we want to share. They have been documented elsewhere, but no harm in repeating in case its helpful. The first is an upgrade to the version of jQuery and an incompatibility with older versions of Visual Composer.

We found a couple of themes where front end components in the theme weren’t working after the upgrade. Looking in Firebug we traced the issue to the following code,

a[href*=#]

searching and replacing it with

a[href*='#']

seemed to do the trick nicely and we were back in business.

Visual composer is a bit more tricky, generally what we found was that the backend editor wouldn’t load. If you bought the plugin separately then an update should be available, if you got it bundled with a theme, then your vendor should be able to support you and supply you with a new version of the theme or plugin.

If you have a recent version available, then a quick fix seems to be to replace the backend.min.js file from /wp-content/plugins/js_composer_theme/assets/js/dist.

If you are running the standard version of the plugin then the best plan is probably to overwrite the files using FTP with a the latest version (4.11.2.1) taken from a theme update or if you have a license for the standalone version of the plugin (it’s about US$35 IIRC). Should be a straight swap, but be careful if you have a very old version of the plugin running.

cURL and HTTPS

I had an odd problem the other day whilst building a new WordPress-based ticketing site with payment integration with PayPal Pro. The standard PayPal integration worked fine, but the Pro version kept giving me errors saying that it couldn’t connect to PayPal.

The vendor was quick to reply, but wasn’t much help. Their first suggestion was to upgrade the plugin, which didn’t change anything, and the second was to disable all other plugins, which didn’t help either.

So I downloaded the site to my Mac, ran it using MAMP and used the excellent HTTP Scoop to check whether it was really connecting to PayPal. The answer was no, so I delved into the code and started to look at what it was doing.

The answer was that it was using cURL to connect to PayPal. So I ran a quick test to explore why it wasn’t working and found that:

  1. It worked fine with an HTTP URL
  2. Although there were various suggestions around using directives, specifying alternate protocols etc, none of these seemed to work with the PayPal server

So I wondered whether it might work in curl at the command line (the -v is for verbose output).

curl -v https://api-3t.sandbox.paypal.com/nvp

That gave a message which suggested that there was a problem with the SSL handshake.Researching a little further, it seemed that there might be a problem with openssl or the version of curl itself.

At this point I didn’t want to start messing with the version of curl on my Mac, but went instead and tried on a development server that I had access to and upgraded the version of openssl to 1.0.1. That seemed to resolve the problem there, so I then checked on the client’s server and whilst they were running openssl 1.0.1, their version of curl was relatively old (7.19.0) so, after checking the backups I upgraded curl and it worked at command line. A quick run of my test script suggested that it was working, and when I went back to the site, the integration was working properly.  I should add that I didn’t have to upgrade PHP itself.

So there you go, if you can’t get cURL connecting via SSL, check your openssl and curl versions and check that both are up to date.

DNS Oddities in OSX

I recently encountered some weirdness with DNS in OSX that I thought I’d share, in case it came in helpful for anyone.

The scenario was that a client’s website displayed fine on my laptop with the plain variant of the email (e.g. http://domain.com), but the www variant was pointing to the server’s default page. Pinging the server from Terminal in my Mac yielded the same IP address for both, so all looked good.

Initially I thought that it was a server configuration issue, so checked all the settings, but there was nothing obvious.

I then checked the DNS records for the domain thinking that perhaps we didn’t change both variants when we went live (the site was done in a hurry and went live late at night), but everything looked fine.

Then, clutching at straws, I added a test file to the server’s default site to make sure I was really looking in the right place, and realised that I was looking at my Apache server, not the Windows one I expected.

At this point I realised that something odd must be going on with DNS, so went to the server in Remote Desktop and checked in the browser there. The www variant worked. Then I checked on my phone and it also worked, so something odd was definitely going on with my Mac.

At this point it occurred to me to open the hosts file, and to my surprise it seemed I’d added an entry for the www variant of the domain for the previous version of the client’s website (which was WordPress, hence the Apache server) literally years ago (in fact, OSX must have migrated the hosts file from my old laptop).

So the morals of the story are:

  1. Never forget that OSX is too clever by half
  2. Don’t trust the IP address yielded by ping in Terminal on a Mac, try a third-party service to be sure.

Suppressing Previews in Outlook.com

If you use Outlook.com (Hotmail as-was), you’ll notice that it has an annoying habit of adding previews when you add in a URL. These previews are composed of the site’s metadata plus a picture, usually the logo (though sometimes it can be a bit random what gets thrown up), and as far as we can tell, you can’t turn them off.

If you’re a regular user you’ll just click the link to remove the preview and be done with it. Unfortunately, following deployment of a new website for a client, their email signature started including a preview below the link to their website when it was replied to using Outlook.com, the client wasn’t happy and, even though we were pretty sure it wasn’t our fault, we were required to find a resolution. Removing the link to their website from the email footer wasn’t an option we were told.

Once we could repeat the problem, we looked at how to prevent it from happening. We demonstrated that it wasn’t just their website, the same problem occurred even if we changed the link to Amazon.com or Google.com. Unfortunately we couldn’t find much in the way of answers, so we were on our own.

Going back to first principles, we looked at adding rel=”nofollow”, and then realised that we could prevent the problem occurring if we took the link out of the table tags that (quite reasonably) had been used to govern layout. We tried reformatting the signature with div tags, but the problem recurred. We then wondered what would happen if we rearranged the order of links, at which point a eureka moment occurred, Outlook.com was picking the content of the first link it came across.

The solution was then straightforward. We added an empty hyperlink <a href=”#”></a> before the link to the client’s website, and the problem went away. Presumably Outlook.com finds the link, sees it links to no-where and stops. Result!

Adding WPML Taxonomy Translations Via Code

This is really obscure, but hopefully helpful to someone.

When you are using WordPress, this enables you to add a translation for an existing taxonomy term and associate it with the original. For example, when you are using WPML and creating posts via the WordPress API from an XML feed or similar.

So basically you pass in the details of your new term, the taxonomy name, the ISO language code you are targeting and the ID of the existing taxonomy. I lifted this from an existing sample, but  amended it so the slug was unique (I was lazy and just add the language code to the original), and also fixed an issue where the correct id wasn’t being returned.

Enjoy!

/* MT 2015-10-29 Enables Categories to be Programatically Added
    (str) $term is the text of the term you want to add.
    (str) $taxonomy is the name of your custom taxonomy.
    (str) $language_code is the two letter code of the language you want to save the term in.
    (int) $content_id is the ID of the term in the default language to associate with the new term.
    @ returns (bool) false on error or if term exists. (int) 0 for no affected rows and term object on success.
*/
function wpml_insert_term($term, $taxonomy, $language_code, $content_id) {
    
    $slug = "";
    $old_term = get_term( $content_id, $taxonomy );
    $slug = $old_term->slug . '-' . $language_code;
    
    $new_term = false;
    //if(!term_exists($term, $taxonomy) && taxonomy_exists($taxonomy)){
    if(taxonomy_exists($taxonomy)){
        $new_term = wp_insert_term($term, $taxonomy,array('slug' => $slug));
        
        if(isset($new_term['term_id'])){
            // Include WPML API
            include_once( WP_PLUGIN_DIR.'/sitepress-multilingual-cms/inc/wpml-api.php' );

            global $wpdb;
            $update = $wpdb->update( 
                $wpdb->prefix.'icl_translations', 
                array( // data
                    'trid' => wpml_get_content_trid( 'tax_'.$taxonomy, $content_id), 
                    'element_type' => 'tax_'.$taxonomy, 
                    'language_code' => $language_code, 
                    'source_language_code' => wpml_get_default_language()
                ), 
                array( // where
                    'element_id' => $new_term['term_id'],
                    'element_type' => 'tax_'.$taxonomy
                )
            );
            
            $new_term = ($update === false || $update === 0) ? $update : $new_term;
            
        }
    }
    return $new_term;
}

Sorting HTML Option lists with jQuery

I’ve recently been working on a WordPress plugin for a client that includes the ability to filter the results via multiple select boxes, with the contents of the select boxes themselves filtered so only the relevant options are shown.

It’s a nice little solution that I’d love to show off, but alas, I’m NDA’s and can’t talk about work for that client.

What I can share though is a neat little solution for sorting the contents of select lists alphabetically. It’s borrowed from elsewhere on the web, so not my own work, but useful nonetheless.

var options = $('select.whatever option');
    var arr = options.map(function(_, o) {
        return {
            t: $(o).text(),
            v: o.value,
            s: $(o).prop('selected')
        };
    }).get();
    arr.sort(function(o1, o2) {
        return o1.t > o2.t ? 1 : o1.t < o2.t ? -1 : 0;
    });
    options.each(function(i, o) {
        o.value = arr[i].v;
        $(o).text(arr[i].t);
        $(o).prop('selected', arr[i].s);
    });

Capturing Traffic from .NET Services with Fiddler

If you haven’t used it previously, Fiddler is an amazing tool for tracking network activity from Windows* and invaluable when you want to watch communication between your browser and web servers.

It’s also really handy for watching communication between your web server and third parties, which is really handy if you want to intercept web service calls and see what is going on.If you’re working with ASP.NET and IIS there’s a really neat trick to route your traffic through Fiddler.

The first step is to install Fiddler on the target machine using Remote Desktop. When Fiddler launches and attaches, it adjusts the current user’s proxy settings to point at Fiddler, running on 127.0.0.1:8888 by default. That means that traffic from most applications automatically flows through Fiddler without any additional configuration steps.

However, when you want to capture web service calls from an ASP.NET page, you need to take additional steps. The easiest way to do this is to add a few lines of code to your web.config file. The nice thing about this is that if shouldn’t affect other sites running on the same server.

To do this, open web.config and add the following code at the bottom file the file within the <configuration> element, or update the system.net element if it exists .

<system.net>
    <defaultProxy enabled = "true" useDefaultCredentials = "true">
        <proxy autoDetect="false" bypassonlocal="false" proxyaddress="http://127.0.0.1:8888" usesystemdefault="false" />
    </defaultProxy>
</system.net>

Make sure that Fiddler is running then save the file. Traffic from services should begin to flow through Fiddler:

image

When you’re done debugging, be sure to reverse the changes to web.config. If you forget to undo your changes, you’re likely to find that all of your services can no longer reach the network the moment that Fiddler is shutdown.

*If you are Mac-based check out HTTPScoop

Backup Strategies for WordPress

For even the smallest WordPress site, not having an effective backup strategy in place can mean a small issue with your website resulting in a prolonged period of downtime, losing your place in search engine rankings and many hours of valuable time being taken up trying to piece a site back together. If your website is a shop and/or includes significant amounts of user data, then the loss can be catastrophic and something that can sink your business. Fortunately, there are plenty of tools out there that can help, and with a small investment of time, you can be prepared for the worst.

It’s sometimes said in IT that you haven’t backed up properly unless your data is in at least three places, and used at least two separate backup methods. This is something we definitely agree with and encourage. If one set of backups are somehow inaccessible, then having a second set taken using an alternative mechanism increases the probability of recovery significantly.

The first step is to document your website. Make sure you have at least the following in a document, printed out and filed where it can be found in case of a disaster. Usually we don’t advocate writing down passwords, but this is an exception to the rule, you should password-protect your electronic copy though.

  • DNS registrar details and control panel login
  • IP address of your site and host control panel login details
  • Emergency contact details for your host
  • Your WordPress database connection details
  • Your WordPress dashboard login
  • Details of your theme and plugins
  • Details of any third party services you use and logins, such as MailChimp, PayPal etc.
  • Details of passwords for backups.

The next step is to make sure that your website is being backed up. We usually go with a two-pronged approach. The first is to have the host back-up the server and database. The usual pattern is to take a full backup each week (often on a Saturday or Sunday night), then an incremental backup each night that picks up changes. Keeping backups for the previous 4 weeks is usually a good trade-off between not taking up too much space and being able to go back a reasonable distance in time in case you find that a problem has existed for a while.

It goes without saying that you should check on a regular basis that your backups are running correctly (setting up email alerts is ideal) and that the files can be accessed. Unfortunately it can sometimes be difficult to do a test restore as it will result in your website being overwritten, but it’s generally a good idea to try out a backup and restore just before you send your website live. One thing to be wary of is that databases get backed up properly. Just backing up files is often not enough and in order to be able to restore your database you’ll need to have run a database-specific backup routine in place to dump the data. If you do this, make sure you keep a note of where it gets saved, and the steps you’ll need to perform to restore it.

The second prong of our approach is to use BackupBuddy. This is a brilliant plugin for WordPress which is a true “Swiss Army Knife” of backup. Our preferred strategy is to take a weekly full backup of the website, then nightly backups of the database, with a 4 week retention period. It’s usually enough unless you are continually loading files onto the site, in which case you’ll want to do a full backup more often.

One of the nice features of BackupBuddy is that it will send your backups to a number of different locations, including FTP, Dropbox, AWS and their own proprietary “Stash”. My preferred location is to leave the files on the web server and to send them to Dropbox as I have something like a TB of storage that I’m not otherwise using and it’s easy for me to get at the files from just about anywhere should I need to. One tip is to set the backup folders not to synchronise with your local machine to save bandwidth and your disk space. As with server backups, it can be handy to set BackupBuddy to remind you by email when it has run, and you should check from time to time that files are being saved to the right place.

The other nice thing about BackupBuddy is the ease of which you can restore files not just to your web server, but an alternative location, for example, if you want to check the contents of a backup on a test domain, or if you want to move your site to a new host. All you need is the zip of your backup (either the full or database-only version) and a  file called importbuddy.php. Upload both to the root of your website using FTP, then run importbuddy.php in a web browser and follow the simple on-screen instructions.

The other nice thing about the importbuddy process is that it will update your wp-config.php file and database should you change the domain or database server details. As such, it’s also a really useful tool during development, for example, when you want to move a site from a development to production server (or visa versa), but that’s something for another day.