Categories
Blog

Lazy Loading images in WordPress

While WordPress Core is working towards their own Native Lazy Loading of images, I have been using something for a while already to do the job. I’m sure I found this from, or was inspired by, someone else’s code but I don’t recall where. If it is your code, please leave a comment so that I may correctly attribute it.

Step one

The first step is to hook into the wp_get_attachment_image_attributes filter to override the in-built src, srcset, and sizes attributes set by Core. We rename these attributes to data-$attribute_name. The new image data doesn’t do anything by itself. We must move it to the correct place using a small shim in the second code snippet below: (Both snippets may be placed into your theme’s functions.php file)

<?php add_filter( 'wp_get_attachment_image_attributes', 'lazyload_images', 99 ); function lazyload_images( $attr ) { $return = []; foreach ( $attr as $key => $value ) { switch( $key ) { case 'sizes': case 'src': case 'srcset': $key = "data-$key"; break; } $return[ $key ] = $value; } $return['class'] .= ' lazyload'; $return['loading'] = 'lazy'; return $return; }

Step two

For the second, and final, step, we print a small bit of JavaScript into the footer of our site to load a fallback script. Alternatively, we rewrite the data-$attribute_name attributes back to their original names for native lazy loading. This code detects at load time whether the browser supports native lazy loading, or we need to use something else to mimic it. In this case the fallback script we use is LazySizes.js:

<?php add_action( 'wp_footer', 'native_lazyload_handler' ); function native_lazyload_handler() { ?> <script> if ('loading' in HTMLImageElement.prototype) { const images = document.querySelectorAll('img.lazyload'); images.forEach(img => { img.sizes = img.dataset.sizes; img.src = img.dataset.src; img.srcset = img.dataset.srcset; }); } else { // Dynamically import the LazySizes library const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.2.2/lazysizes.min.js'; script.async = true; document.body.appendChild(script); } </script> <?php }

Last thoughts

You might recall, we also add the class name of lazyload in the first snippet. So, if the browser doesn’t support native lazy loading then the LazySizes.js fallback loads. This uses the data-$attribute_name attributes unchanged. Those we also set in the first snippet.

If, however, the browser does support native lazy loading then we simply rewrite the data-$attribute_name back to their original names. Then we let the browser do its thing. In this case, we don’t load any extra JavaScript.

For even faster load times we set the LazySizes script to the async load method. With this, the browser loads it asynchronously without blocking the page render. This means that the Time Till First Meaningful Paint is quicker because the browser doesn’t wait for the script to load. Once LazySizes loads, or the attributes rewritten for Native Lazy Loading, then the images pop into place as soon as they are visible. Both browser native lazy loading and LazySizes 5.0+ support loading without the page jumping about as the images are loaded. To do this, they use the width and height attributes. These attributes indicate the correct aspect ratio of the image, which the browser and LazySizes use to cut out the right amount of space for the image.


Photo by Matilda Wormwood from Pexels

Categories
Blog

Fakecam Open Source Virtual Background

In a post by Benjamin Elder there is a nice proof-of-concept app. This app is based on the Bodypix.js AI/ML library. Ben’s article about their Open Source Virtual Background explains the inner workings. Using Ben’s code, I created a Snap Package called Fakecam. I also include a nice User Interface, which allows easy configuration of the options.

Screenshot of my Fakecam User Interface

Performance issues

Next, I convinced several members of the Ubuntu Podcast Telegram channel to give Fakecam a test run. Among those members is Stuart Langridge. When testing, Stuart finds that the speed on their machine is woefully bad. It turns out that using TensorflowJS in NodeJS is slow. This is made worse by having to copy the image between Python and NodeJS. This copy goes over an HTTP link, slowing everything down. The result is a very slow pictures.

First attempt to fix

TensorflowJS is sped up if you have a NVidia graphics card with the CUDA API. However, I feel that if I rely on this requirement it would severely limit the scope of the app. After trawling through the TensorflowJS GitHub repository I see an interesting area. There is code to use a WebGL-based API. This, when running inside a React Native app.

React Native is made to run on mobile devices, which often don’t use NVidia graphics. So, using NVidia CUDA just is not good enough. The code I found in platform_react_native.ts uses OpenGLES. It extends TensorflowJS’ already working WebGL code. With this idea, can I also use a native OpenGL stack with NodeJS? That means I can use WebGL on a desktop or laptop?

With a lot of effort, and lots of Cola and Coffee, I work through several evenings until morning. Now, the NodeJS-based TensorflowJS talks to my AMD graphics device via OpenGL. The speed is faster on my powerful desktop PC by a large margin. To do this, I copy the React Native Platform abstraction for TensorflowJS. This gives me a TensorflowJS platform-library for WebGL in NodeJS is in my Fakecam GitHub repository.

Fakecam works well now?

Well not quite. I gave the updated version of Fakecam back to Stuart who ran it on their laptop again. While the speed is not as bad as it was, Stuart still finds this version is slow. The image is just too slow to be usable. Oh dear, back to the drawing board.

Second attempt…

The Python side of this app is using OpenCV, which also supports running AI models. Now we’re using Bodypix.js with TensorflowJS. So, the next logical step, then, is remove the NodeJS side entirely. That way the images stay in the Python app. This removes the copying between Node and Python via HTTP.

Hold your horses, it’s not that easy.

I converted the Bodypix.js model to a more standard Tensorflow model. But, giving this to OpenCV it complains that it can’t work the model. OpenCV’s support for part of the AI model is not complete in the current release. I am a good community member, so I wrote a Bug on the OpenCV GitHub page. After a few days, the authors have a fix added to the OpenCV code that makes the model work.

SUCCESS

Finally, with the new OpenCV code from the Bleeding Edge, I can load the Bodypix AI model. Continuing, I re-write the last JavaScript code as Python. But the output from OpenCV, and Tensorflow, have different shapes. So, this takes a lot of guessing to find out.

So, now, I load the images into any available hardware. And, with the images in the hardware, I keep them there until the end. Then, I pull the images back out and put them into the Video4Linux loop-back device. Now, apps such as Zoom or Skype show the new video as an option.

Fakecam version 2.0!

Hooray! This updated version is even faster than the interim version. It works much faster than the original version. And there is another side-effect. The Python-only version cuts-out the background more accurately! Win-win!

Get it from the Snap Store

Categories
Blog

Awesomify anything or anyone with OpenFaaS!

While I’ve been lurking about the OpenFaaS Community I haven’t really had the wherewithal to get myself knuckled down to build something that might be classed as useful or fun. To remedy that I finally produced a new idea for a function that I can publish into the FaaS Store. I’m calling this function “Awesomify”. It will take any text you throw at it and make it awesome!

Photo by Jon Tyson on Unsplash

First thing I need is a Kubernetes cluster. After a quick trip down to Marks and Sparks to fill my trolly with juicy servers, I remembered that this is supposed to be serverless computing, plus M&S is a clothing store so I wouldn’t get servers there anyway. Putting the servers back on the shelves I instead fired up Google Cloud’s dashboard and ordered some Kubernetes with a side order of Chips (Fries for folk over the pond).

Following the OpenFaaS documentation and my serverless system is now fully deployed, and it was easy (mostly, I had a couple of hiccups from following the docs too closely which I’ve filed bugs about so they should get resolved soon).

The function

Now to my function. Which language or framework should I use to build it? NodeJS? Pass. Go? Hmm, interesting idea, but nah. BASH? Now you’re talking; you can’t get more esoteric than that! Let’s write an entire function using BASH…

Photo by Luca Bravo on Unsplash

For my function to work, I need some sound clips. So, pulling out my scissors I found a cassette of Tegan and Sara’s greatest hits and started hacking away. After 36 hours of toil, I finally had a series of clips that are usable and a large pile of wasted audio tape.

The only thing missing now is a voice generator. While I could use a cloudy serverless service such as Amazon’s Polly or Google’s Cloud TTS I decided that open source was the way forward. There’s a little-known project called Mycroft which creates a completely open source Intelligent Assistant like Amazon Echo, Google Assistant, or Apple Siri. They have released a piece of code they named “Mimic” to perform text to speech duties.

As an aside, my good friend Alan Pope from Canonical lent his voice to the Mimic TTS engine and the Mycroft assistant so this choice of engine was even more fun for me.

With the function taking shape I felt ready to publish a trial run onto my test cluster on Google Cloud. Two hours after publishing it and tweeting a few times the function has been hit 396 times and nobody has complained since I increased the timeouts and minimum instance count from their defaults.

Photo by William Stitt on Unsplash

And we’re off to the races!

A Pull Request is now into the OpenFaaS Store GitHub repository to add the function for anybody to use with a simple clickity-doodle. If you don’t have or want your own instance of the function you may use the test that is still operational. You just need to point your web browser to https://openfaas.bowlhat.net/function/awesomify?q=OpenFaaS. By changing the text after the “?” you can tailor what is awesome to your own needs. (Make sure you replace spaces in the text with a + symbol because addresses need to be “URL Encoded”)

A few examples I’ve tried are:


My source code is published at GitHub.

Categories
Blog

Pure CSS Loading Animation

Highlighting my skills in Web Development where I am constantly pushing the boundaries, here is my CSS Loading Animation. The experiment here uses CSS keyframes to achieve sixty frames per second animation without repainting the elements.

To build the animated object (the spinner) I use a pair of incomplete CSS Triangle tricks. When you combine the CSS Triangle trick with border-radius you find you can curve one edge of the triangle. However, I reinvented this method, but I haven’t seen any prior art.  The nice Home button on this site’s menu bar shows how I use a single rounded triangle.

As I saw that the single rounded triangle worked quite well. So, I started experimenting, leading me to the complete circle design you see in the spinner.

The effect is created by hacking the CSS Triangle trick to display two opposing triangles instead of one directional arrow. This is created with two non-transparent borders instead of one, which would create a single arrow:

.selector { border-left: 25px solid transparent; border-right: 25px solid transparent; border-top: 25px solid #eee; border-bottom: 25px solid #eee; }

Once we have the opposing triangles, we apply a 50% border radius on the element. This forces a circular appearance with two slices and two gaps. Finally, we create a sibling using the :after CSS selector providing the remaining two slices in the gaps from the first element:

.selector:after { border-left: 25px solid #ccc; border-right: 25px solid #ccc; border-top: 25px solid transparent; border-bottom: 25px solid transparent; }

The first example shows an effect like Apple’s “Beach Ball”. Both elements animate together. Because the same look can be achieved without two separate elements, the second demo shows a use for keeping them separate:

So, we use two separate elements to create this slightly different effect. Here, we animate each pair of opposite triangles separately. The effect is pleasing:

Categories
Blog

How to make the A-Z Listing plugin for WordPress use a different Index Letter for a post

This post talks about our A-Z Listing Plugin, which is available on WordPress.org.

How did we get here?

After a lengthy battle with a very considerate person in the WordPress.org forums where I repeatedly failed to get them working with various attempts at writing code they could drop into their site, I decided I needed to write it up and explain how to do this once and for all.

The scenario

  • You have a series of posts with Proper Nouns (people’s names) as their title
  • You want to index them on their Family Name (sometimes called the “Last Name”)

The concept is simple, in that you need to hook into the filter that I’ve provided and return the right result with the index letter changed. This is the rub in my attempt at helping the person on WordPress.org in that I really didn’t understand my own code well enough, despite having written it, so I kept suggesting non-working solutions.

The final code

add_filter( 'a_z_listing_item_indices', 'my_a_z_index_filter', 10, 3 ); function my_a_z_index_filter( $indices, $item, $item_type ) { // make sure we're filtering the right post type if ( 'post-type-we-want' === get_post_type( $item ) ) { // pull the title and get the first letter of the second word $full_name = explode( ' ', $item->post_title ); // the last word is in the last element of $title_parts so check it is there $last_name = array_pop( $full_name ); // ensure we actually found a last name if ( $last_name ) { // cut the first letter out for our index $index = substr( $last_name, 0, 1 ); // set up a new empty array $indices = array(); // only the first names are left in $full_name. Join them together again $first_names = join( ' ', $full_name ); // Now put the last name first and separate with a comma+space from the first names $formatted_name = "{$last_name}, {$first_names}"; // add the new name associated with the item into the new array we created $indices[ $index ][] = array( 'title' => $formatted_name, 'item' => $item, ); // return a new array with our new index letter instead of the // indices already discovered by the plugin return $indices; } } // if we get here we didn't override the indices so return // those already discovered. return $indices; }

The new way (Jan 2019)

Since this post was published, I have added a new filter that is much more friendly to use. The new filter does not require a specific format for the return value. Instead, it just needs an array of letters for the post to be indexed against.

add_filter( 'a_z_listing_item_index_letter', 'my_a_z_index_filter', 10, 3 ); function my_a_z_index_filter( $index_letters, $item, $item_type ) { // make sure we're filtering the right post type if ( 'post-type-we-want' === get_post_type( $item ) ) { // pull the title and get the first letter of the second word $full_name = explode( ' ', $item->post_title ); // the last word is in the last element of $title_parts so check it is there $last_name = array_pop( $full_name ); // ensure we actually found a last name if ( $last_name ) { // cut the first letter out for our index $index = substr( $last_name, 0, 1 ); // set up a new empty array overwriting the old indices $index_letters = array( $index ); } } // return the indices item's indices return $index_letters; }
Categories
Blog

Advanced composition of Polymer Webcomponents

In a request for help sent to the Polymer web components mailing list, a user wondered about lists specifically based on the example provided in the Shop Demo that the Polymer team created. This user wanted to understand how to change the list so that it may use a different mark-up to the one provided for in the original example.

As I thought about and researched this problem, I encountered a stack overflow post that talks about a parent providing the mark-up for a dom-repeat template inside a child’s Shadow Root. This led me to experimentation with multiple levels of nesting where only the top-level element or document provided the mark-up templates for a list and the list items within that list.

Mark-up included in the document

My top-level document that I settled upon dictates how the children behave. Notably, each element’s innards are wrapped inside a <template> to prevent display when the child elements stamp the Light DOM into their Shadow Root.

<my-list items="[[items]]"> <template item-outer> <my-list-item item="[[item]]"> <template item-inner> <img src="[[item.icon]]" /> </template> </my-list-item> </template> </my-list>

The reference to a variable named items maps to the following array of objects (purely an example):

[ { "title": "cat", "icon": "https://placekitten.com/128/128/" }, { "title": "random", "icon": "https://unsplash.it/128/128/" } ]

The magic isn’t so much in the above invocation, but the individual elements my-list, and my-list-item. They both follow similar layout but need slight differences due to the my-list-item not being able to hijack a dom-repeat template like the my-list is able to.

The my-list Element

<dom-module id="my-list"> <template> <content></content> <template is="dom-repeat" id="repeater" items="[[items]]></template> </template> <script> Polymer({ is: "my-list", properties: { items: { type: Array, value: function() { return []; }, notify: true } }, ready: function() { this.$.repeater.templatize(this.querySelector('[item-outer]')); Polymer.Bind.prepareModel(this.$.repeater); Polymer.Base.prepareModelNotifyPath(this.$.repeater); } }); </script> </dom-module>

The magic is achieved via the combination of the insertion point (<content></content>) providing the templated contents from the Light Dom, and the templatize() function. The function takes a querySelector match of the <template> tag from the Light Dom by matching on an attribute I assigned. Because I then assign that template to the dom-repeater template stub inside the element definition when the dom-repeat cycles through the items array and stamps itself to this element’s Shadow Root it will use the code from the Light Dom as the actual rendered output for each item.

This element has a property that holds the items array, which is then assigned to the dom-repeat template for iteration.

The my-list-item Element

With very similar behaviour to the my-list element, the my-list-item element is largely identical with only minor differences to account for using a <template> that doesn’t, unlike the dom-repeat above, stamp itself to the DOM automatically.

<dom-module id="my-list-item"> <template> <p>[[item.title]]</p> <content></content> <template is="dom-template" id="tmpl"></template> </template> <script> Polymer({ is: "my-list-item", properties: { item: { type: Object, value: function() { return {}; }, notify: true } }, ready: function() { this.$.tmpl.templatize(this.querySelector('[item-inner]')); Polymer.Bind.prepareModel(this.$.tmpl); Polymer.Base.prepareModelNotifyPath(this.$.tmpl); var stamped = this.$.tmpl.stamp({item: this.item}); this.appendChild(stamped.root); } }); </script> </dom-module>

This element has a property which holds a single item object as provided by the dom-repeat in our parent element my-list. We follow the same pattern as in the list element excepting that, due to using a <template> which does not automatically stamp itself into the DOM, we include two extra lines of JavaScript, which I’ve highlighted in bold above.

The first extra line stamps the template into a variable with the item property passed through to the template under the same name. Finally, we add the stamped template into the shadow root with appendChild().

I have immortalised the full code in a working example at Codepen

What now?

With this example, it should be possible to see how advanced composition can be achieved allowing for complex scenarios where supporting elements can provide for themselves to be extended without their knowledge. The example of a list taking a list-item template is the most obvious one given our nascent experience with web components but developing this concept can open many new patterns and behaviours.

If you’re a web developer and still haven’t dipped your toe into the pool of web components and Polymer, then I urge you to read more and try out some simple examples. Take your own website and find one thing, no matter how small, which is repeated over multiple pages but currently takes more code to reproduce than you’d like. With that thing, try turning it into a fully self-contained web component and replace ever instance of it throughout your site with an instance of the component instead. Finally start thinking of other more complex things that are repeated and try componentizing those, too. Before you know it, I hope that you’ll be knee-deep into the world of components and are better-off for it.

Furthering your skillset

Some resources that are helpful for beginner and advanced developer alike include:

Categories
Blog

Stop discouraging women!

This post is inspired by an advert that I saw on YouTube that highlights the damage that can happen to a young woman’s psyche with simple behaviour patterns such as telling the woman that she needs to be pretty or even just telling her she is pretty.

I thoroughly agree with the sentiment that many of our brightest female engineers, mathematicians and developers are being discouraged before they even know that they have an interest or aptitude for technical subjects. The Raspberry Pi Foundation is helping in the general push to get more children and young adults to discover the computing realm, but we still have a long way to go until the numbers of children progressing into technical subjects at college and beyond are back where they were in the late 1980s and 1990s.

More, the disparity between male and female students on these STEM courses is very evident. We, as a society, need to encourage young adult women to discover an interest in technical or scientific endeavours. The more we can balance the scales the better and more equal the world will be. This is not just a benefit to the communities that are currently biased toward males but the world, in general, will benefit with new points-of-view pushing technical and scientific discoveries which will filter into every-day life whether the general population realise it or not.

Equality is not just about ensuring that people aren’t discriminated based on gender, age, religion, race, sexual orientation, or planet-of-birth; a truly equal society benefits not just those that might previously be discriminated but those that would be the discriminators, equally!

Categories
Blog

All about the WordPress Fields API

Have you heard about the effort lead by Scott Clark with guidance from Helen Hou-Sandi to develop a WordPress Feature Plugin mysteriously entitled “WordPress Fields API”? What is it, what does it do, and why should you care?

Feature Plugins

First-up we need to understand what a Feature Plugin is in relation to WordPress Core:

When the WordPress community decided that we needed a major rewrite of the Administration screens it was realised that such an invasive change would be difficult to develop within Core’s source-code repository. The reasoning is that regular releases of WordPress are likely to be required before the MP6 (as the admin revamp was called) code was ready for the World.

As an upshot of this dichotomy between regular releases and long-term development of code that is likely to be broken many times before it’s ready, the plan was concocted to do the development of MP6 as a plugin. As this plugin was planned to be merged into WordPress Core when it became ready it was dubbed a “feature plugin”. Thus, the concept of Feature Plugins was born, and now most larger development efforts are worked-on in this manner.

What is the Fields API then?

Now we know what a Feature Plugin is, we can explore what the Fields API is:

I alluded to it above, the Fields API is being developed as a Feature Plugin. The idea behind this feature is to provide an API that WordPress and plugins & themes can utilise to add arbitrary data structures to every object that WordPress handles. These objects include posts, both from the in-built post-types and custom post types, navigation menu items, comments, users, and settings.

Why do I care?

While it may not be something you interact with knowingly, the Fields API should pervade everything you do with WordPress no matter whether you’re a visitor, member, author, or administrator. Every time you enter data into a WordPress site, we hope that this will be via a form-field created, output, and saved, by the Fields API.

Plugins and themes will be able to use the API to replace all their custom solutions for form-fields. A previous attempt at unifying some of the admin area settings pages was implemented which we call the Settings API. However, this is only part of the battle, and we anticipate that the Fields API will serve as the back end to the Settings API in addition to being used elsewhere by non-settings-related forms.

When can I get it?

Thus far a small dedicated team including myself and lead by Scott have been working on getting a proof-of-concept out of the door for user-profile screens. This effort is nearing readiness but there will still be a lot of work to complete once this POC is done. Right now, the feature plugin isn’t ready for testing, but we hope that it will be soon. If you’re interested in helping-out with development, you can join us on the WordPress Slack channel #core-fields where several people hang-out and discuss plans. The source-code for the WordPress Fields API Feature Plugin is hosted at GitHub under Scott’s account; please Fork the code, comment on or create issues in the tracker, fix bugs, and file Pull Requests if you spot anything you can help with or can advise improvements or talking-points about.

Categories
Blog

TimThumb EOL (finally!)

The Make WordPress blog has finally signalled the end of a disastrous piece of software that made many WordPress sites insecure. TimThumb is/was supposed to allow embedding of images at any dimensions without requiring WordPress to previously have created the variant. The project has been used by many, many, themes available on commercial sites such as ThemeForest and quite a few that have been published in WordPress.org’s repositories.

The problem is that the project has been plagued by insecurity after vulnerability after blatant holes ever since it launched. Thankfully WordPress.org has signalled that their hosted repositories will no longer allow TimThumb to be included in plugins or themes uploaded from now-on. That means new plugins and themes cannot be added with the code, but still allows existing plugins and themes to have a period of respite as the plugin isn’t being retroactively banned just yet.

The move, in my opinion, is long overdue but at least it’s done now and we can all move forward using more standardised methods such as the in-built add_image_size functionality that Core provides out of the box.

Categories
Blog

Banner bar

I’ve made my first foray into the world of Web Components by making one of my very own. Called Banner-bar it allows to create a simple horizontal banner along the top of a page with support for a logo and link. The banner has a nice shadow offsetting it from the content below and is fully responsive.

Check out the example and code at GitHub