bnks.xyz

Menu

Tag: code

Working with Algolia Places address autocompletion api

For a recent mapping project I implemented Algolia Places for address autocompletion to turn an address into latitude and longitude for querying the database. In the past we’ve used Google Maps, but since this project wasn’t using Google Maps for the map display, using the Places API just for Geocoding is against their terms of use. It turns out this was a blessing in disguise – Algolia is fast, easy to implement, and very affordable. There was however one small hitch – the documentation get’s a bit patchy when you go past a basic implementation. To be fair to them – it’s actually because they start presuming that you’ll be using their multipurpose algoliasearchLite.js library rather than the simpler places.js.

Setting up autocompletion

The example from the documentation only needs a small extension to setup – populating hidden latitude and longitude fields from the returned data by using the ‘change’ event:

<script>
var places = places({
    appId: 'YOUR_PLACES_APP_ID',
    apiKey: 'YOUR_PLACES_API_KEY',
    container: address_input
});
places.on('change', function(e) {
    address_input.textContent = e.suggestion.value
    latitude_input.value = e.suggestion.latlng.lat || '';
    longitude_input.value = e.suggestion.latlng.lng || '';
});
</script>

Reverse geocoding

To give users a number of options, we also provided a geolocation button that uses the Geolocation API to let them search using the location reported by their system. The API returns latitude and longitude coordinates. While this is all that is needed to query the database – the UX isn’t ideal as it wouldn’t give a user readable representation of the location. This is important in case the returned location is wrong. Converting the coordinates into an address is called reverse geocoding.

The Places documentation has an example of reverse geocoding but unfortunately this is one that uses the wrong library. While there isn’t official support for Places, Algolia staff do monitor StackOverflow and help where they can. Luckily one such employee, Oliver, saw my query and got me on the right track.

To make a query you pass a compound latitude/longitude string value, and then an object of any options you want to change. For example:

places.reverse(
    '52.817078,-4.5697185',
    { hitsPerPage: 1 }
)

In another difference from algoliasearchLite.js – the response when using places.js is just the array of results. This makes utilising the results trivial. For example:

places.reverse(
    '52.817078,-4.5697185',
    { hitsPerPage: 1 }
).then(function(response){
    var suggestion = response[0];
    if (suggestion && (suggestion.suburb || suggestion.city)) {
        address_input.value = suggestion.suburb || suggestion.city || suggestion.county;
        address_input.value += ', ' + suggestion.country;
    }
});

Here I’ve chosen to populate the address text input field with the town (aka suburb) if available, and then the country. This gives enough information to orientate the user with what search is being done, without distracting them with the potentially/likely inaccurate house number and road level data.

From my experience so far I’d highly recommend you evaluate Algolia Places for your next autocompletion or geocoding project. The only downside I’ve found, common to all providers that rely on OSM data, is that you can’t reliable search by UK postcodes. In a subsequent post I’ll cover implementing getAddress.io – an API to turn UK postcodes into addresses using the Royal Mail PAF data.

Reverse relationship query for last ACF repeater sub-field

Advanced Custom Fields (ACF) is a great WordPress plugin for adding custom meta fields. It has a very useful relationship field that can be used to denote a connection from one post to another – importantly this is a one-way relationship. When you are on PostA you can generate a list of all the posts that it is linked to.

Going in reverse

ACF documentation highlights how a clever WP_Query can be used to do a `reverse query`, i.e. when you view PostB you can get a list of all the posts that link to PostB.

What about sub-fields

The reverse query works fine as it is for top level fields, but does not work for sub-fields within, for example, a repeater. Luckily Elliot on the ACF support forum shared some code for doing a reverse query against a sub-field.
The key is just using a LIKE for the meta query.

Note – for a Relationship field, where the value is a serialised array, use:

'meta_query' => array(
	array(
		'key' => 'fieldName', // name of custom field
		'value' => '"' . get_the_ID() . '"', // matches exaclty "123", not just 123. This prevents a match for "1234"
		'compare' => 'LIKE'
	)
)

but for a Post Object field, where the value is an integer, use:

'meta_query' => array(
	array(
		'key' => 'fieldName', // name of custom field
		'value' => get_the_ID(),
		'compare' => '='
	)
)

Latest item in repeater only

Just to get more complicated, now let’s do a reverse relationship query, against a sub-field, but only the sub-field within the latest item in the repeater…
Imagine a post type of Business that has a repeater called ‘Audit’, and within it sub-fields for ‘Audit firm’ and ‘Fee’. The ‘Audit firm’ sub-field is a relationship to another post type called Auditor. On the single Auditor pages I want to show the name of each Business who they are currently auditing, i.e., where they are the ‘Audit firm’ in the last repeater entry.

To get a list of Business post IDs we have to use a $wpdb query; the key is the use of MAX(meta_key) to get the last item in the repeater. This works because ACF names it’s repeater fields repeaterName_X_fieldName, where X is the number denoting when the item was added.

The solution

The code below is heavily based on a Stack Overflow answer from Elliot (coincidence?) with added WordPress and ACF magic and help from Luke Oatham.

$meta_key = 'audit_%_audit_firm'; // meta_key for repeater sub-field.
$meta_value = '%"'. get_the_id() . '"%'; // meta_value, wrapped for use in a LIKE.
$post_status = 'publish';
$businesses = $wpdb->get_col( $wpdb->prepare(
	"
	SELECT businessMeta.post_id // Field we want in the returned column.
	FROM $wpdb->postmeta businessMeta
	INNER JOIN
		(SELECT post_id, MAX(meta_key) AS latestAuditRepeater
		FROM $wpdb->postmeta
		WHERE meta_key LIKE '%s'
		GROUP BY post_id) groupedBusinessMeta
	ON businessMeta.post_id = groupedBusinessMeta.post_id
	AND businessMeta.meta_key = groupedBusinessMeta.latestAuditRepeater
	WHERE meta_value LIKE '%s'
	AND abMeta.post_id IN
		(SELECT ID
		FROM $wpdb->posts
		WHERE post_status = '%s')
	",
	$meta_key,
	$meta_value,
	$post_status
) );

Avoiding permissions problems when creating Zip files in PHP

A typical PHP snippet to create a Zip file looks something like this:

$zip = new ZipArchive();
$zipname = 'package_name.zip';
if ( true === $zip->open( $zipname, ZipArchive::CREATE ) ) {
    $zip->addFromString( 'file_name.txt', $file_contents );
    $zip->close();
    header( 'Content-Type: application/zip' );
    header( 'Content-disposition: attachment; filename=' . $zipname );
    header( 'Content-Length: ' . filesize( $zipname ) );
    readfile( $zipname );
    unlink( $zipname );
    exit;
}

But did you ever stop to think about where the temporary ‘package_name.zip’ file is created? Neither have I. What I have come across, are permissions errors when creating zip files as well as the slightly more mysterious 0Kb Zip files.

Watching the filesystem and removing the unlink() reveals that the Zip file is created in the current working directory, i.e. “the path of the ‘main’ script referenced in the URL”. For most web applications or CMS this will mean the root of the application/CMS.

This is fine when you have fairly relaxed permissions, but if things are more locked down you end up with the errors described above as the temporary file can’t be created.

A simple solution

As is so often the case the solution is actually very simple – tell PHP to move it’s working directory using the chdir() function. To keep things re-usable, we can combine chdir() with another function that returns the temporary directory specified in php.ini – which should always be writable by PHP – sys_get_temp_dir().

Below is the updated snippet, with one extra feature – it stores the temp file with a random name to reduce the liklihood of collisions if multiple people access your script at once.

chdir( sys_get_temp_dir() ); // Zip always get's created in current working dir so move to tmp.
$zip = new ZipArchive;
$tmp_zipname = uniqid(); // Generate a temp UID for the file on disk.
$zipname = 'package_name.zip'; // True filename used when serving to user.
if ( true === $zip->open( $tmp_zipname, ZipArchive::CREATE ) ) {
    $zip->addFromString( 'file_name.txt', $file_contents );
    $zip->close();
    header( 'Content-Type: application/zip' );
    header( 'Content-disposition: attachment; filename=' . $zipname );
    header( 'Content-Length: ' . filesize( $tmp_zipname ) );
    readfile( $tmp_zipname );
    unlink( $tmp_zipname );
    exit;
}

Extending WP CLI – wp config update

One gap in the abilities of WP CLI at the moment is the ability to modify an already existing wp-config.php file.

v1.2 introduced the --force flag to overwrite an existing one, but that is the sledgehammer option – so I started working on it myself. I have put a very initial version on GitHub and would welcome feedback and pull-requests. Please don’t use this on a live site!

Is this something you would use? What features do you think it should have? Let me know in the comments.

Displaying you WordPress.org favourite plugins

Updated 02 – 05 – 18: plugins object is now returned as an array.

On a whim this May bank holiday, tucked up on the sofa watching movies, I decided to create a plugin to display my favourited plugins on WordPress.org.

After a bit of digging I found you can use the plugins_api() function and pass it a username, e.g.:

plugins_api( 'query_plugins', array( 'user' => emirpprime, 'per_page' => '-1' ) );

This returns an object with some information about the results, then an array of plugins. A stripped down example of the structure is below:

stdClass Object
    (
    [info] => Array
        (
            [page] => 1
            [pages] => 0
            [results] => 57
        )
    [plugins] => Array
        (
            [0] => Array
                (
                    [name] => Autoptimize
                    [slug] => autoptimize
                    [version] => 2.1.0
                    [author] => <a href="http://blog.futtta.be/">Frank Goossens (futtta)</a>
                    [author_profile] => https://profiles.wordpress.org/optimizingmatters
                    [requires] => 4.0
                    [tested] => 4.7.5
                    [compatibility] => Array
                        (
                        )
                    [rating] => 94
                    [ratings] => Array
                        (
                            [5] => 419
                            [4] => 23
                            [3] => 12
                            [2] => 8
                            [1] => 22
                        )
                    [num_ratings] => 484
                    [support_threads] => 121
                    [support_threads_resolved] => 81
                    [downloaded] => 1349088
                    [last_updated] => 2016-12-14 5:45am GMT
                    [added] => 2009-07-09
                    [homepage] => http://blog.futtta.be/autoptimize
                    [sections] => Array
                        (
                            [description] => Autoptimize makes ...
                            [installation] => Just install from your WordPress...
                            [faq] => Installation Instructions...
                            [short_description] => Autoptimize speeds up your website and helps you save bandwidth by aggregating and minimizing JS, CSS and HTML.
                            [download_link] => https://downloads.wordpress.org/plugin/autoptimize.2.1.0.zip
                            [screenshots] => Array
                                (
                                )
                            [tags] => Array
                                (
                                    [css] => css
                                    [html] => html
                                    [javascript] => javascript
                                    [js] => JS
                                    [minify] => minify
                                )
                            [versions] => Array
                                (
                                    [0.1] => https://downloads.wordpress.org/plugin/autoptimize.0.1.zip
                                    ...
                                    [trunk] => https://downloads.wordpress.org/plugin/autoptimize.zip
                                )
                            [donate_link] => http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
                            [contributors] => Array
                                (
                                )
                        )
                )
        )
)

A simple loop over the plugins array will get all the details about a plugin you could want.

A short while later, and a rough and ready version is complete – a basic plugin that registers a shortcode and returns a list of a user’s plugins.

What does the plugin output?

Here are my favourites as an example – the markup is basic but easy to style, with a couple of classes for targetting. I’ve kept it simpler than the layout in wp-admin or the plugin repository, but hopefully with enough info to be useful:

Found: 65

  • Add Descendants As Submenu Items by Alex Mills (Viper007Bond)
    Automatically all of a nav menu item's descendants as submenu items. Designed for pages but…
  • Autoptimize by Frank Goossens (futtta)
    Autoptimize speeds up your website by optimizing JS, CSS, images (incl. lazy-load), HTML and Google…
  • Blacklist Updater by pluginkollektiv
    Automatic updating of the comment blacklist in WordPress with antispam keys from GitHub.
  • Broken Link Checker by ManageWP
    This plugin will check your posts, comments and other content for broken links and missing images, and notify you if any are found.
  • Bulk Add Terms by Sohan Zaman
    A lightweight plugin to add thousands of taxonomy terms in one go.
  • Classic Editor by WordPress Contributors
    Enables the previous "classic" editor and the old-style Edit Post screen with TinyMCE, Meta Boxes, etc. Supports all plugins that extend this screen.
  • Classic Editor Addon by Pieter Bos, Greg Schoppe
    This free "Classic Editor Addon" plugin makes sure that the new block editor cannot be…
  • Client-proof Visual Editor by Hugo Baeta
    Simple, option-less, plugin to make TinyMCE - the WordPress Visual Editor - easier for clients…
  • Cloudflare by John Wineman, Furkan Yilmaz, Junade Ali (Cloudflare Team)
    All of Cloudflare’s performance and security benefits in a simple one-click install of recommended settings specifically developed for WordPress.
  • Code Snippets by Shea Bunge
    An easy, clean and simple way to run code snippets on your site.
  • Coming Soon Page & Maintenance Mode by SeedProd by SeedProd
    The #1 Coming Soon Page, Under Construction & Maintenance Mode plugin for WordPress.
  • Custom Post Type UI by WebDevStudios
    Admin UI for creating custom post types and custom taxonomies for WordPress
  • Debogger by Simon Prosser
    Debugging tool for theme authors and reviewers.
  • Developer by Automattic
    A plugin, which helps WordPress developers develop.
  • Disable Comments by Samir Shah
    Allows administrators to globally disable comments on their site. Comments can be disabled according to post type. Multisite friendly.
  • Disable REST API by Dave McHale
    Disable the use of the JSON REST API on your website to unauthenticated users.
  • Disable WP REST API by Jeff Starr
    Disables the WP REST API for visitors not logged into WordPress.
  • Duplicate Post by Enrico Battocchi
    Copy posts of any type with a click!
  • Duplicator – WordPress Migration Plugin by Snap Creek
    WordPress migration and backups are much easier with Duplicator! Clone, back up, move and transfer an entire site from one location to another.
  • Email Address Encoder by Till Krüss
    A lightweight plugin that protects email addresses from email-harvesting robots, by encoding them into decimal…
  • Enable Media Replace by ShortPixel
    Easily replace any attached image/file by simply uploading a new file in the Media Library…
  • Epoch – A native Disqus alternative with a focus on speed and privacy by Postmatic
    Epoch - 100% realtime chat and commenting in a tiny little package that is fully…
  • EWWW Image Optimizer by Exactly WWW
    Speed up your website and improve your visitors' experience by automatically compressing and resizing images…
  • FakerPress by Gustavo Bordoni
    FakerPress is a clean way to generate fake and dummy content to your WordPress, great…
  • Flickr Justified Gallery by Miro Mannino
    Just your beautiful Flickr photos. In a Justified Grid.
  • Google Analytics Dashboard for WP by ExactMetrics (formerly GADWP) by ExactMetrics
    Connects Google Analytics with your WordPress site. Displays stats to help you understand your users and site content on a whole new level!
  • Gravity PDF by Gravity PDF
    Automatically generate, email and download PDF documents with Gravity Forms and Gravity PDF.
  • If Menu – Visibility control for Menu Items by Layered
    Display tailored menu items to each visitor with visibility rules
  • iThemes Security (formerly Better WP Security) by iThemes
    iThemes Security is the #1 WordPress Security Plugin
  • Lazy Load by Mohammad Jangda
    Lazy load images to improve page load times and server bandwidth. Images are loaded only when visible to the user.
  • Lazy Load by WP Rocket by WP Rocket
    Lazy Load your images and iframes, replace Youtube videos by a preview thumbnail.
  • List Pages Shortcode by Ben Huson, Aaron Harp
    Introduces the [list-pages], [sibling-pages] and [child-pages] shortcodes for easily displaying a list of pages within a post or page.
  • Liveblog by WordPress.com VIP, Big Bite Creative and contributors
    Empowers website owners to provide rich and engaging live event coverage to a large, distributed…
  • MCE Table Buttons by Jake Goldman, 10up, Oomph
    Adds table editing controls to the visual content editor (TinyMCE).
  • Meteor Slides by Josh Leuze
    Easily create responsive slideshows with WordPress that are mobile friendly and simple to customize.
  • Open Graph Protocol Framework by itthinx
    The Open Graph Protocol enables any web page to become a rich object in a social graph. This plugin renders meta tags within an extension framework.
  • Page Links To by Mark Jaquith
    Lets you make a WordPress page (or port or other content type) link to a URL of your choosing (on your site, or on another site), instead of its norma …
  • PDF Image Generator by Mizuho Ogino
    Generate automatically cover image of PDF by using ImageMagick. Allow user to insert PDF link…
  • Plugin Check by Manoj Thulasidas
    Plugin Check is a validation tool for PHP developers (and a quality checker for end…
  • PWA by PWA Plugin Contributors
    WordPress feature plugin to bring Progressive Web App (PWA) capabilities to Core
  • Really Simple SSL by Rogier Lankhorst, Mark Wolters
    No setup required! You only need an SSL certificate, and this plugin will do the…
  • Redirection by John Godley
    Manage 301 redirections, keep track of 404 errors, and improve your site, with no knowledge of Apache or Nginx needed.
  • Redis Object Cache by Till Krüss
    A persistent object cache backend powered by Redis. Supports Predis, PhpRedis, HHVM, replication, clustering and WP-CLI.
  • Regenerate Thumbnails by Alex Mills (Viper007Bond)
    Regenerate the thumbnails for one or more of your image uploads. Useful when changing their sizes or your theme.
  • REST API Toolbox by Pete Nelson
    Allows tweaking of several REST API settings
  • Restricted Site Access by Jake Goldman, 10up, Oomph
    Limit access to visitors who are logged in or allowed by IP addresses. Includes many…
  • Safe Report Comments by Thorsten Ott, Daniel Bachhuber, Automattic
    This plugin gives your visitors the possibility to report a comment as inappropriate. After a…
  • Sidebar Login by Mike Jolley
    Easily add an ajax-enhanced login widget to your WordPress site sidebar.
  • Simple History by Pär Thernström
    View changes made by users within WordPress. See who created a page, uploaded an attachment…
  • Stream by XWP
    Planes have a black box, WordPress has Stream. When something goes wrong, you need to…
  • Subscribe To Comments Reloaded by WPKube
    Subscribe to Comments Reloaded allows commenters to sign up for e-mail notifications of subsequent replies.…
  • Tabify Edit Screen by CodeKitchen B.V.
    Enable tabs in the edit screen and manage them from the back-end.
  • Theme Check by Otto42, pross
    A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool!
  • WordPress Beta Tester by Peter Westwood, Andy Fragen
    Allows you to easily upgrade to Beta releases.
  • WordPress Zero Spam by Ben Marshall
    Zero Spam makes blocking spam comments a cinch. Install, activate and enjoy a spam-free site.…
  • WP Content Filter – Censor All Offensive Content From Your Site by David Gwyer
    Take control and protect your site today! Censor all content containing profanity, swearing, offensive, and…
  • WP Document Revisions by Ben Balter
    WP Document Revisions is a document management and version control plugin. Built for time-sensitive and mission-critical…
  • WP Lynx by John Havlik
    WP Lynx allows you to mimic Facebook's wall links in your WordPress posts.
  • WP Maintenance Mode by Designmodo
    Adds a splash page to your site that lets visitors know your site is down for maintenance. It's perfect for a coming soon page.
  • WP Offload Media Lite for Amazon S3, DigitalOcean Spaces, and Google Cloud Storage by Delicious Brains
    Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFro …
  • WP Retina 2x by Jordy Meow
    Make your website look beautiful and crisp on modern displays by creating and displaying retina images. WP 4.4+ is also supported and enhanced.
  • WP TinyMCE Tables by Adam Pope
    Adds the table controls to the TinyMCE editor in WordPress
  • WP-Optimize by David Anderson, Ruhani Rabin, Team Updraft
    WP-Optimize is WordPress's most-installed optimisation plugin. With it, you can clean up your database easily and safely, without manual queries.
  • Yet Another Related Posts Plugin (YARPP) by YARPP
    Display a list of related posts on your site based on a powerful unique algorithm.…
  •  

    What do you think? Is there any other info you think would be useful to include? Let me know in the comments.

    Sending your WordPress posts back / forward in time

    Fancy sending your WordPress site back (or forward) in time for a day? Thanks to the multitude of filters it only takes a few lines of code. In this example I’m just going to filter the_time(), but in a future post I will also show you how to put together a more comprehensive function that uses multiple filters (and has a more practical use).

    The filter for the_time() passes two values in – the value it was going to display, and the formatting string used to create it.

    Hooking in to the filter

    This is fairly standard – pass the name of the filter we are using to the function add_filter(), along with the name of our custom function that is going to modify the value:

    add_filter( 'the_time', 'cc_time_machine' );

    However, since we need both of the arguments that the filter passes, we have to add in the optional values for ‘priority’ and ‘accepted arguments’. The default priority is ten, and as mentioned there are two arguments – so that gives us:

    add_filter( 'the_time', 'cc_time_machine', 10, 2 );

    Travelling in time:

    Now we can receive the data in our function and modify the value. None of the arguments relate to the ID of the post being dealt with, but we can use the global `$post` variable to retrieve it. Then we use the get_the_time() function to retrieve the date/time of the post in timestamp format – this makes it easy to manipulate. Let’s send everything 30 days into the past:

    $timestamp = get_post_time( 'U', true, $post );
    $adjusted = $timestamp + ( -30 * DAY_IN_SECONDS );

    Finally, we need to return the new value. Utilising the second argument ensures we format the date in the same way as it was originally requested:

    return date( $format, $adjusted );

    The complete function:

    N.B. this version reads the time travel value ($offset) from the database so it can be controlled through wp-admin.

    Managing multiple WordPress installs with bash and WP CLI

    Jump to the bottom if you want to go straight to the script

    I recently set up a new VPS on DigitalOcean and chose to manage the web stack and sites with EasyEngine. I’m very impressed with EashEngine, but the fact it makes deploying sites so easy shows up how much overhead there is in staying on top of multiple WordPress installs.

    As the recent vulnerability in the REST API showed, keeping on top of updates is really crucial. In the past I’ve used a management system called InifinteWP, but I’ve decided I would rather use fewer tools and instead rely on WP CLI.

    The key commands

    There are four basic commands key to staying on top of updates:

    wp core check-update
    wp core update
    wp plugin list
    wp plugin update --all

    They’re self explanatory, and with these you can find out if there are any updates available, and apply them.

    Scalability

    But logging in to a server, navigating to the web directory, and running potentially four commands is not exactly time saving. Especially when you need to be doing this in a daily basis to ensure critical patches are applied as soon as possible. (Monitoring the vulnerability disclosure lists is a topic for another day.)

    Luckily we can easily automate this with a simple bash script with just a few essential steps:

    • find all WordPress installs and loop over them
    • navigate into their directory
    • run the two WP CLI commands needed to check for updates to core and plugins
    • repeat

    Once the basics work the script can be easily extended with options such as a choice between checking for updates or doing updates.

    EasyEngine hiccups

    The standard way of finding a WordPress install so you can use WP CLI is to search for wp-config.php files since you can be certain it exists. Then navigate to the directory where you found it, and execute the command.

    However, EasyEngine uses a security conscious directory structure with wp-config.php outside htdocs. This is very sensible, but impacts WP CLI the commands won’t run here – we need to move down into the htdocs directory. One solution is to just add a cd htdocs, but that would mean the script becomes specific to this server setup. Instead, just choose another core file / directory to search for – I went for /wp-admin.

    The script

    There are many ways this could be extended or customised – but this gist covers the basics and should be flexible enough to cover both EasyEngine and non-EasyEngine setups:

    Why ask when you can be told

    The last piece of the puzzle is combing the script with cron and mail.

    Instead of logging in each day to run the script and check for updates, we can use cron to run it and email the output. This means I can wait for the server to tell me when I need to log in and run an update, and not have to constantly check.

    For example, on Ubuntu you can $ sudo crontab -e then add 30 6 * * * su myuser -c '/home/myuser/wp_helper.sh | mail -s "WP Helper update checker" "myuser@domain.co.uk" # run wp_helper.sh at 0630 daily and email.' to run the script at 630 am every day and email the result. Note – this adds the cron job to the root crontab; this means that it will be run as root and so WP CLI will throw a warning. To avoid this su myuser -c runs the command as a chosen user.

    I want to review changlogs and test before updating, so am only running the script in check mode. If you are happy auto-updating you could either pass the relevant arguments to the script or use the native WordPress functions.

    Get terms from a shared taxonomy used on a single post type

    WordPress has a handy get_terms() function that retrives a list of all the terms for a taxonomy – this is great if you are, for example, building a <select> box for filtering a custom post type listing page. But there’s one big problem, if you use this on a shared taxonomy, it will show all terms even if they aren’t used on the particular post type you are dealing with. There is a hide_empty argument that you can pass to get_terms, but this only excludes terms that aren’t used for the default “post” post type.

    What to do about it

    Facing this today, I ended up with this little snippet that utilises a $wpbd query along with get_terms to achieve what we want:

    • First it uses a nested select query to get the IDs for all posts in our custom post type, this is then immediately utilised by the outer select query to grab a list of term IDs from the term_relationships table
    • Then this list of IDs is passed into get_terms
    • Finally it’s output to build the select box

    You’ll also notice in there it is being cached as a transient for 4 hours. Depending on the nature of your site and server you might not need this, or may need to adjust the duration.

    The key parts to modify if you want to utilise this is post_type='cpt' on line 8 and 'taxonomy' => 'country' on line 9. These set the custom post type you want to retrive terms for, and the name of your taxonomy respectively.

    Using Garlic.js with TinyMCE WYSIWYG editor

    Garlic.js is a great library – it uses localStorage to save the state of forms, so if your users accidentally close the tab or browser before submitting, their entry isn’t lost. This works seemlessly for almost all form elements, however WYSIWYG editors like TinyMCE present problems. Luckily it isn’t hard to fix – there’s a comment on the github repository for the project with the snippet you need to add to the init function:

    setup : function(editor) {
        editor.on("change keyup", function(e){
            console.log('saving');
            //tinyMCE.triggerSave(); // updates all instances
            editor.save(); // updates this instance's textarea
            $(editor.getElement()).trigger('change'); // for garlic to detect change
        });
    }
    

    So far so easy. But today the challenge was a little harder as WordPress was in the mix too.

    At Helpful Technology we have a training product called Crisis90 that allows users work through a scenario and compare their responses. It is built on WordPress and makes use of GravityForms to allow users to submit responses to the crisis scenarios presented (there’s also a simulated Twitter environment for practicing real-time responses). When asking users to draft a press release, for example, we provide a WYSIWYG editor – this is native to GravityForms which in turn leverages the bundled TinyMCE library in WordPress. But this means that TinyMCE is being loaded automatically without me being able to modify the init function. Luckily there is a filter for that – tiny_mce_before_init. This filter lets you modify the settings array used to initialise TinyMCE. Despite the lack of a setup item in the defaults or example, it is perfectly valid. You can use this filter in a simple plugin or in your theme’s functions.php:

    As you can see, we’re just adding a setup key to the $settings array containing the snippet from above. I’ve also included a little check that we aren’t in the admin area as I only want this to apply to the instances of TinyMCE used in forms on the front-end of the site.
    Now Garlic.js will function correctly with TinyMCE, and a slip of the finger won’t lead to any lost work.

    Uses of modulus – rows for grids and background colours

    There are two things that designers will throw out quite often – box grids with rows, and repeating background colours.

    Sounds easy – but go and try it within the WordPress loop (or any other). It can get ugly quickly, but the solution is actually simple: Modulus. In PHP it’s the % sign.

    To see what modulus is all about run this simple page:

    This will output a list showing when various modulus calculations will output TRUE so you can check in an if statement. For example:

    $i % 3 == 2: 
    0 :  
    1 :  
    2 : TRUE 
    3 :  
    4 :  
    5 : TRUE 
    6 :  
    7 :  
    8 : TRUE 
    9 : 

    Simple example – inserting rows for a grid

    Modulus 3 is perfect for creating a 3 column grid (in this case in Bootstrap style) as we can check for when the remainder is 2 which will tell us we are on the 3rd, 6th, 9th etc item. This means we can output the very first and last <div class="row"> tags with no logic, then just use modulus to insert the inbetween </div><div class="row"> to end one row and start another where needed:

    More complex example – looping background colours

    This time we will use modulus 7 to loop over a list of the colours of the rainbow to set a class that will control the background colour of a div:

    This illustrates how the modulus number sets the frequency that the loop repeats, and by checking for different remainders you can identify any point in that loop.

    If you’ve got a good use of modulus let me know in the comments.