SVG Sanitization

A couple of days ago I was browsing through the WordPress core Trac looking for something to get involved in and stumbled upon the following issue: https://core.trac.wordpress.org/ticket/24251

The lack of ability to upload SVGs into WordPress has always been a slight annoyance to me so I decided to see what I could do about it. After reading through the thread, I realised that what PHP was really missing, was a decent SVG sanitizer.

I read around a few articles and read through the source at: https://github.com/cure53/DOMPurify to get some ideas of how it’s done by the professionals. I started off by mapping out what was needed:

  • An element whitelist
  • An attribute whitelist
  • A way to remove those not in the whitelist

The two whitelists I borrowed from DOMPurify, after all it’s built by people with more knowledge than me. I then put a basic PHP library together that allowed me to pass in a dirty SVG string and receive out an SVG string with all the non-whitelisted elements and attributes removed.

The strangest thing I came across whilst building this was the fact that DOMNodeList doesn’t work like an array. If you iterate from 0 to 10 and delete node 5, everything drops down 1 place, so when you move to node 6, that’s actually node 7, odd. This can be easily fixed of course by iterating backwards from 10 to 0.

Anyway, I have a basic POC up on Github (https://github.com/darylldoyle/svg-sanitizer) that I’m hopefully going to push a bit further in the next week or so. Lets hope all goes well!

 

WordPress InnoDB Issues

I’ve been working with a lot of WordPress plugins recently and have come across a bug that had me stumped for a while, therefore, I thought it’d be worth sharing it here.

After installing and activating a plugin that created new database tables, I realised that the tables had not been installed. I contacted the plugin support who suggested re-installing WordPress. Reluctantly I did this but it didn’t help at all, I therefore decided I’d dig into the issue and see if I could track it down.

A bit of work and a few var_dump()‘s later I found that there as an error with the database creation SQL (below)

CREATE TABLE IF NOT EXISTS wp_domain_mapping (
    id BIGINT NOT NULL AUTO_INCREMENT,
    blog_id BIGINT NOT NULL,
    domain VARCHAR(255) NOT NULL,
    active TINYINT DEFAULT 1,
    PRIMARY KEY (id),
    KEY blog_id (blog_id, domain, active)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci

I ran the query manually and realised it was returning the error Specified key was too long; max key length is 1000 bytes. I’d never seen this error before, so I dug into it a little more, this page informed me that InnoDB has a maximum key size of 1000 bytes, unless the innodb_large_prefix flag is set in MySQL in which case the maximum size is 3072 bytes.

That said, I found the following document where I could check the storage requirements of each field type. From this, I can tell that the BIGINT field, blog_id is 8 bytes, the TINYINT field, active is 1 byte and as UTF8 needs 3 bytes per character, the domain field is 255 * 3 bytes or 765 bytes. This gives us a total key length of 774 bytes.

It was then that I realised that I wasn’t using standard UTF8 but utf8mb4, which WordPress has set as it’s default character set as of 4.2. utf8mb4 requires 4 bytes per character and therefore the domain field calculation was wrong and was actually 255 * 4 bytes or 1,020 bytes in length. This is now an issue as our key is bigger than the size allowed by InnoDB hence the issue creating the tables.

Now as far as I can see, there is only one real way of getting around this and it’s the method WordPress has chosen, reducing the field length from 255 chars to something less, 247 in this case.

Now I know about this it shouldn’t be much of an issue, but I wonder how many plugin developers aren’t going to realise this has changed and are going to run into this. I foresee it being a major pain for a few months.

Anyway, onwards and upwards now!

Cheers for now!

PSR-4 Autoloading in WordPress

Recently I’ve been tasked with integrating a few API’s into WordPress sites. Whilst this doesn’t seem too hard, I found it hard to find solid documentation on the best practices in this scenario.

In this post I will explain how I decided to go about these integrations, focussing mainly on my class loading inside WordPress.

Why Autoload?

Themes in WordPress all seem to be very procedural. This is fine for a little theme, but as soon as you start making a few changes, that functions.php file becomes unwieldy pretty quick. I’ve seen people split up their functions files into separate files, each holding functions for a certain part of the site. That’s not bad, but then you’ve got to make sure you include them all into your functions.php file which looks horrendous!

By structuring your code properly, you can move your function calls into classes, these classes can then be autoloaded using PHP’s spl_autoload_register function. Autoloading means no more including files, as long as your register function knows where to look for the code, it will include is for you. Doesn’t that sound good?

How it’s done

Rather than write my own autoloader, I opted to use the Class Example autoloader, defined by the php-fig, which is available here. I add this file, as autoloader.php to my theme root, this is then included into the top of the functions.php file.

In the demo below, I have a folder called Services that holds all of my API classes, these classes are then in turn contained within the services namespace. On line 16 I am passing this namespace into the autoloader and then telling it the location of these classes. Remember, as they are in the theme directory, we need to prefix the folder with the theme directory location, hence the use of the get_template_directory() function.

You can call the addNamespace method as many times as you like with different namespaces and directories, if your classes are split up a little more.

Now what?

Now we’ve registered our autoloader we can call classes as and when we need them without having to worry about including the file each time, whether that be from the functions.php file or from inside a template, it doesn’t really matter as they’re always available. You will however have to call the class with it’s full namespace or make use of the use statement in PHP to import that namespace.

Further Reading

If you’d like to know more about namespacing and autoloading classes, there are some great resources below:

Adding zoom level to Advanced Custom Fields maps.

We use Elliot Condon’s Advanced Custom Fields extensively in WordPress at work and I must say, it’s one of my favourite WordPress plugins ever made. That said, sometimes people ask for things that I just can’t work out how to do with the native plugin.

Today a client asked me to allow them to set their own zoom distance on their maps. We’re using the great ACF map field for all the maps so I thought, “Hey, that’s fine, I’ll just go and enable that option”, only to find that there isn’t an option for this. I did some digging around on Google and stumbled across a support thread that asks exactly what I wanted to know.

Whilst there was an answer in the thread, it required me to change the plugin files, something I plain up refuse to do. The last thing I want is for somebody to update their plugins at some time in the future and the whole thing to fall apart. No, I had to find a way of doing this without hacking into any other files.

I came up with the idea that I’ll use a separate field and the client can set their zoom level in there. Whilst that worked fine for me as I know the zoom levels, it wouldn’t be too great for the client, who wants to just be able to zoom in on the map and have that set. After reading through the code samples in the aforementioned support thread, it hit me that I should be able to bind to the zoom_change event in the Google Maps API and then output the value into the second field for use on the front end.

Upon first try, I ran into issues with google not being defined. This was down to the map not being loaded when my javascript was fired. I tried firing my function on window.load() but I still had the same issue. Somehow I had to delay the function until the Google API had loaded.

I ended up doing this by using a setInterval() on a 500ms interval to call a function that checks if typeof google !== 'undefined'. If this returned true, I could then cancel the interval and bind to the maps API. The second problem I ran into, was that I wasn’t sure how to access the ACF maps object. After looking around the ACF plugin file, I worked out that it’s set in js/input.js under the acf.fields.google_map.map object. I added this to my maps callback and found out that it wasn’t yet defined. This was then added to the previous variable check function and hey presto, it worked. Now it was just a case of linking the fields up, the easy bit.

Below are the files that I used. adminMaps.js handles the heavy lifting and setting of the fields whereas the snippet from my functions.php just makes sure that the JS file is only loaded on post.php in the admin area.

To use this, all you’ll have to change is the selector for the second field, on lines 10 and 18 of adminMaps.js, it’s currently set to #acf-field-zoom_level the ID of my field.

You can also access the full Gist here.

P.S. As a bonus, line 13 of the JS file will disable the scroll to zoom in the admin area!

Pure CSS Image Slider

Recently I’ve became more and more interested in CSS3 use on the web. This interest stems from the fact that more and more people are moving from using JavaScript to manipulate items on the the DOM to using CSS3 Keyframe animations and Transforms.

Up until now, I have only used CSS3 for nth-child selectors and other little bits, mainly leaning back on JavaScript to do the heavy lifting. Today, after reading around, I decided to attempt to create a pure CSS image slider. As an object of webpages that I use often, I know how I like mine to work, which should allow me to get it as good as I can.

I used Codepen to mock up this demo, the code you can see below!

See the Pen Pure CSS Slider by Daryll Doyle (@darylldoyle) on CodePen.

One of the major issues I ran into was the fact that I needed to fix the amount of slides as to calculate the percentages used in the keyframes animation. I’d have liked to overcome this, by passing a variable to either the keyframe declaration, or by creating a custom keyframe animation per slider inside the slider mixin. As far as I can see, neither of these options are currently implemented so I’m a bit out of luck there, if you can think of another way in the meantime, drop me an email, or drop a comment on this post!